Greasy Fork is available in English.

AI Chat Sidebar

AI对话侧边栏,支持多AI提供商配置

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         AI Chat Sidebar
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  AI对话侧边栏,支持多AI提供商配置
// @author       You
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @license      GPL-3.0
// @connect      *
// @require      https://cdn.jsdelivr.net/npm/[email protected]/marked.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js

// ==/UserScript==

(function() {
    'use strict';

    // 配置管理
    // Trusted Types 策略支持
    let ttPolicy;
    if (window.trustedTypes && window.trustedTypes.createPolicy) {
        try {
            ttPolicy = window.trustedTypes.createPolicy('ai-chat-sidebar-policy', {
                createHTML: (string) => string
            });
        } catch (e) {
            console.warn('Failed to create Trusted Types policy:', e);
        }
    }

    const safeInnerHTML = (element, html, fallbackText) => {
        if (!element) return;
        try {
            if (ttPolicy) {
                element.innerHTML = ttPolicy.createHTML(html);
            } else {
                element.innerHTML = html;
            }
        } catch (e) {
            console.warn('innerHTML assignment failed:', e);
            element.textContent = fallbackText !== undefined ? fallbackText : html;
        }
    };

    const ConfigManager = {
        get: (key, defaultValue) => GM_getValue(key, defaultValue),
        set: (key, value) => GM_setValue(key, value),
        getProviders: () => GM_getValue('ai_providers', []),
        saveProviders: (providers) => GM_setValue('ai_providers', providers),
        getPrompts: () => GM_getValue('prompts', []),
        savePrompts: (prompts) => GM_setValue('prompts', prompts),
        getModels: (providerIndex) => GM_getValue(`models_${providerIndex}`, []),
        saveModels: (providerIndex, models) => GM_setValue(`models_${providerIndex}`, models),
        getAvailableModels: (providerIndex) => GM_getValue(`available_models_${providerIndex}`, []),
        saveAvailableModels: (providerIndex, models) => GM_setValue(`available_models_${providerIndex}`, models),
        getConversations: () => GM_getValue('conversations', []),
        saveConversations: (conversations) => GM_setValue('conversations', conversations),
        getTheme: () => GM_getValue('theme', 'default'),
        saveTheme: (theme) => GM_setValue('theme', theme),
        getSystemConfig: () => GM_getValue('system_config', {defaultModel: null, defaultPrompt: null}),
        saveSystemConfig: (config) => GM_setValue('system_config', config)
    };

    const THEMES = {
        default: {
            name: '默认极光',
            colors: {
                primary: '#667eea',
                primaryGradient: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
                bg: '#ffffff',
                bgSecondary: '#f8f9fa',
                text: '#333333',
                textSecondary: '#666666',
                border: '#e1e4e8',
                hover: '#f1f3f5',
                userMsgBg: '#667eea',
                userMsgText: '#ffffff',
                aiMsgBg: '#f1f3f5',
                aiMsgText: '#333333',
                shadow: 'rgba(0,0,0,0.1)'
            },
            styles: {
                borderRadius: '4px',
                btnRadius: '4px',
                fontFamily: 'inherit',
                borderWidth: '1px',
                shadowLg: '-2px 0 8px rgba(0,0,0,0.1)',
                spacing: '15px',
                fontSize: '14px',
                fontWeight: '400',
                headerHeight: 'auto',
                transition: 'all 0.2s ease'
            }
        },
        notion: {
            name: 'Notion风格',
            colors: {
                primary: '#333333',
                primaryGradient: '#ffffff',
                bg: '#ffffff',
                bgSecondary: '#f7f7f5',
                text: '#37352f',
                textSecondary: 'rgba(55, 53, 47, 0.65)',
                border: '#e9e9e8',
                hover: 'rgba(55, 53, 47, 0.08)',
                userMsgBg: 'transparent', // Notion style: minimal background
                userMsgText: '#37352f',
                aiMsgBg: 'transparent',
                aiMsgText: '#37352f',
                shadow: 'rgba(15, 15, 15, 0.05)'
            },
            styles: {
                borderRadius: '3px',
                btnRadius: '3px',
                fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif',
                borderWidth: '1px',
                shadowLg: '0 0 0 1px rgba(15,15,15,0.02), 0 3px 6px rgba(15,15,15,0.04)',
                spacing: '12px',
                fontSize: '14px',
                fontWeight: '400',
                headerHeight: '45px',
                transition: 'background 0.1s ease'
            }
        },
        youtube: {
            name: 'YouTube风格',
            colors: {
                primary: '#ff0000',
                primaryGradient: '#ffffff',
                bg: '#ffffff',
                bgSecondary: '#f2f2f2',
                text: '#0f0f0f',
                textSecondary: '#606060',
                border: 'transparent', // Flat design
                hover: '#e5e5e5',
                userMsgBg: '#f2f2f2',
                userMsgText: '#0f0f0f',
                aiMsgBg: '#ffffff',
                aiMsgText: '#0f0f0f',
                shadow: 'rgba(0,0,0,0.1)'
            },
            styles: {
                borderRadius: '12px',
                btnRadius: '18px', // Pill shape
                fontFamily: 'Roboto, Arial, sans-serif',
                borderWidth: '0px',
                shadowLg: '0 4px 12px rgba(0,0,0,0.08)',
                spacing: '16px',
                fontSize: '14px',
                fontWeight: '400',
                headerHeight: '56px',
                transition: 'background 0.2s cubic-bezier(0.2, 0, 0, 1)'
            }
        },
        github: {
            name: 'GitHub风格',
            colors: {
                primary: '#2da44e',
                primaryGradient: '#24292f',
                bg: '#ffffff',
                bgSecondary: '#f6f8fa',
                text: '#24292f',
                textSecondary: '#57606a',
                border: '#d0d7de',
                hover: '#f3f4f6',
                userMsgBg: '#ddf4ff',
                userMsgText: '#24292f',
                aiMsgBg: '#f6f8fa',
                aiMsgText: '#24292f',
                shadow: 'rgba(140,149,159,0.2)'
            },
            styles: {
                borderRadius: '6px',
                btnRadius: '6px',
                fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif',
                borderWidth: '1px',
                shadowLg: '0 8px 24px rgba(140,149,159,0.2)',
                spacing: '16px',
                fontSize: '14px',
                fontWeight: '400',
                headerHeight: '60px',
                transition: 'all 0.2s cubic-bezier(0.3, 0, 0.5, 1)'
            }
        },
        discord: {
            name: 'Discord风格',
            colors: {
                primary: '#5865F2',
                primaryGradient: '#313338',
                bg: '#313338',
                bgSecondary: '#2b2d31',
                text: '#dbdee1',
                textSecondary: '#949ba4',
                border: '#1e1f22',
                hover: '#3f4147',
                userMsgBg: '#5865F2',
                userMsgText: '#ffffff',
                aiMsgBg: '#2b2d31',
                aiMsgText: '#dbdee1',
                shadow: 'rgba(0,0,0,0.2)'
            },
            styles: {
                borderRadius: '8px',
                btnRadius: '4px',
                fontFamily: '"gg sans", "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif',
                borderWidth: '0px',
                shadowLg: '0 0 10px rgba(0,0,0,0.5)',
                spacing: '16px',
                fontSize: '15px',
                fontWeight: '500',
                headerHeight: '48px',
                transition: 'background 0.15s ease-out'
            }
        },
        apple: {
            name: 'Apple风格',
            colors: {
                primary: '#0071e3',
                primaryGradient: 'rgba(255, 255, 255, 0.72)', // Glassmorphism
                bg: 'rgba(255, 255, 255, 0.72)',
                bgSecondary: 'rgba(245, 245, 247, 0.5)',
                text: '#1d1d1f',
                textSecondary: '#86868b',
                border: 'rgba(0,0,0,0.05)',
                hover: 'rgba(0,0,0,0.03)',
                userMsgBg: '#0071e3',
                userMsgText: '#ffffff',
                aiMsgBg: 'rgba(255,255,255,0.5)',
                aiMsgText: '#1d1d1f',
                shadow: 'rgba(0,0,0,0.1)'
            },
            styles: {
                borderRadius: '12px',
                btnRadius: '980px', // Fully rounded
                fontFamily: '-apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", sans-serif',
                borderWidth: '1px',
                shadowLg: '0 20px 40px rgba(0,0,0,0.1)',
                backdropFilter: 'saturate(180%) blur(20px)',
                spacing: '18px',
                fontSize: '15px',
                fontWeight: '400',
                headerHeight: '52px',
                transition: 'all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)'
            }
        }
    };

    const applyTheme = (themeName) => {
        const theme = THEMES[themeName] || THEMES.default;
        const sidebar = document.getElementById('ai-chat-sidebar');
        
        if (!sidebar) return;

        const setVar = (name, value) => {
            sidebar.style.setProperty(`--ai-${name}`, value);
        };

        Object.entries(theme.colors).forEach(([key, value]) => {
            setVar(key, value);
        });

        // Apply default styles if not present in theme
        const defaultStyles = THEMES.default.styles;
        const styles = { ...defaultStyles, ...(theme.styles || {}) };
        
        Object.entries(styles).forEach(([key, value]) => {
            setVar(key, value);
        });
        
        // Special handling for backdrop filter (Apple style)
        if (styles.backdropFilter) {
            sidebar.style.backdropFilter = styles.backdropFilter;
            sidebar.style.webkitBackdropFilter = styles.backdropFilter;
        } else {
            sidebar.style.backdropFilter = 'none';
            sidebar.style.webkitBackdropFilter = 'none';
        }

        // Special handling for header text color based on gradient
        const header = sidebar.querySelector('.sidebar-header');
        if (header) {
            if (themeName === 'notion' || themeName === 'youtube' || themeName === 'apple') {
                header.style.color = '#333';
                header.style.borderBottom = `1px solid ${theme.colors.border}`;
                header.querySelectorAll('button').forEach(btn => {
                    if (!btn.classList.contains('close-btn')) {
                        btn.style.color = '#333';
                        btn.style.background = 'rgba(0,0,0,0.05)';
                    }
                });
                const closeBtn = header.querySelector('.close-btn');
                if (closeBtn) closeBtn.style.color = '#333';
            } else {
                header.style.color = 'white';
                header.style.borderBottom = 'none';
                header.querySelectorAll('button').forEach(btn => {
                    if (!btn.classList.contains('close-btn')) {
                        btn.style.color = 'white';
                        btn.style.background = 'rgba(255,255,255,0.2)';
                    }
                });
                const closeBtn = header.querySelector('.close-btn');
                if (closeBtn) closeBtn.style.color = 'white';
            }
        }
        
        ConfigManager.saveTheme(themeName);
    };

    // 创建侧边栏HTML
    const createSidebar = () => {
        const sidebar = document.createElement('div');
        sidebar.id = 'ai-chat-sidebar';

        // 创建调整大小的手柄
        ['left', 'right', 'top', 'bottom'].forEach(pos => {
            const handle = document.createElement('div');
            handle.className = `resize-handle-${pos}`;
            sidebar.appendChild(handle);
        });
        ['tl', 'tr', 'bl', 'br'].forEach(pos => {
            const handle = document.createElement('div');
            handle.className = `resize-handle-corner-${pos}`;
            sidebar.appendChild(handle);
        });

        // 创建头部
        const header = document.createElement('div');
        header.className = 'sidebar-header';

        const tabs = document.createElement('div');
        tabs.className = 'tabs';
        tabs.id = 'tabs-container';

        ['chat', 'providers', 'prompts', 'system'].forEach((tab, i) => {
            const btn = document.createElement('button');
            btn.className = i === 0 ? 'tab active' : 'tab';
            btn.dataset.tab = tab;
            btn.textContent = tab === 'chat' ? '对话' : tab === 'providers' ? 'AI提供商' : tab === 'prompts' ? '提示词库' : '系统配置';
            tabs.appendChild(btn);
        });

        const controls = document.createElement('div');
        controls.className = 'header-controls';
        
        const themeBtn = document.createElement('button');
        themeBtn.className = 'theme-btn';
        themeBtn.textContent = '🎨';
        themeBtn.title = '切换主题';
        
        const themeDropdown = document.createElement('div');
        themeDropdown.className = 'theme-dropdown';
        Object.entries(THEMES).forEach(([key, theme]) => {
            const item = document.createElement('div');
            item.className = 'theme-item';
            item.dataset.theme = key;
            item.innerHTML = `
                <span class="theme-preview" style="background: ${theme.colors.primaryGradient}"></span>
                <span>${theme.name}</span>
            `;
            themeDropdown.appendChild(item);
        });
        
        const closeBtn = document.createElement('button');
        closeBtn.className = 'close-btn';
        closeBtn.textContent = '×';

        controls.appendChild(themeBtn);
        controls.appendChild(themeDropdown);
        controls.appendChild(closeBtn);

        header.appendChild(tabs);
        header.appendChild(controls);
        sidebar.appendChild(header);

        // 创建内容区
        const content = document.createElement('div');
        content.className = 'sidebar-content';

        // 对话标签页
        const chatTab = document.createElement('div');
        chatTab.className = 'tab-content active';
        chatTab.id = 'chat-tab';

        const chatContainer = document.createElement('div');
        chatContainer.className = 'chat-container';

        const conversationsSidebar = document.createElement('div');
        conversationsSidebar.className = 'conversations-sidebar';
        conversationsSidebar.id = 'conversations-sidebar';

        const chatMain = document.createElement('div');
        chatMain.className = 'chat-main';

        const modelSelector = document.createElement('div');
        modelSelector.className = 'model-selector';
        const modelBtn = document.createElement('button');
        modelBtn.id = 'model-display-btn';
        const modelName = document.createElement('span');
        modelName.id = 'model-name';
        modelName.textContent = '选择模型';
        const arrow = document.createElement('span');
        arrow.className = 'arrow';
        arrow.textContent = '▼';
        modelBtn.appendChild(modelName);
        modelBtn.appendChild(arrow);
        const modelDropdown = document.createElement('div');
        modelDropdown.id = 'model-dropdown';
        modelDropdown.className = 'model-dropdown';
        modelDropdown.style.display = 'none';
        modelSelector.appendChild(modelBtn);
        modelSelector.appendChild(modelDropdown);

        const messages = document.createElement('div');
        messages.className = 'messages';
        messages.id = 'messages';

        const inputArea = document.createElement('div');
        inputArea.className = 'input-area';
        const inputWrapper = document.createElement('div');
        inputWrapper.className = 'input-wrapper';

        const btnContainer = document.createElement('div');
        btnContainer.style.display = 'flex';
        btnContainer.style.gap = '5px';

        const newChatBtn = document.createElement('button');
        newChatBtn.id = 'new-chat-btn';
        newChatBtn.className = 'prompt-icon-top';
        newChatBtn.title = '新建对话';
        newChatBtn.textContent = '➕';

        const promptBtn = document.createElement('button');
        promptBtn.id = 'prompt-selector-btn';
        promptBtn.className = 'prompt-icon-top';
        promptBtn.title = '选择提示词';
        promptBtn.textContent = '💡';

        const paramsBtn = document.createElement('button');
        paramsBtn.id = 'params-selector-btn';
        paramsBtn.className = 'prompt-icon-top';
        paramsBtn.title = '模型参数';
        paramsBtn.textContent = '⚙️';

        const clearBtn = document.createElement('button');
        clearBtn.id = 'clear-chat-btn';
        clearBtn.className = 'prompt-icon-top';
        clearBtn.title = '清除对话';
        clearBtn.textContent = '🗑️';

        const summarizeBtn = document.createElement('button');
        summarizeBtn.id = 'summarize-page-btn';
        summarizeBtn.className = 'prompt-icon-top';
        summarizeBtn.title = '总结网页';
        summarizeBtn.textContent = '📄';

        btnContainer.appendChild(newChatBtn);
        btnContainer.appendChild(promptBtn);
        btnContainer.appendChild(paramsBtn);
        btnContainer.appendChild(clearBtn);
        btnContainer.appendChild(summarizeBtn);

        const textarea = document.createElement('textarea');
        textarea.id = 'user-input';
        textarea.placeholder = '输入消息...';

        inputWrapper.appendChild(btnContainer);
        inputWrapper.appendChild(textarea);

        const sendBtn = document.createElement('button');
        sendBtn.id = 'send-btn';
        sendBtn.textContent = '发送';

        const promptDropdown = document.createElement('div');
        promptDropdown.id = 'prompt-dropdown';
        promptDropdown.className = 'prompt-dropdown';
        promptDropdown.style.display = 'none';

        const paramsPanel = document.createElement('div');
        paramsPanel.id = 'params-panel';
        paramsPanel.className = 'params-panel';
        paramsPanel.style.display = 'none';

        const tempItem = document.createElement('div');
        tempItem.className = 'params-item';
        const tempLabel = document.createElement('label');
        tempLabel.textContent = '温度 (Temperature):';
        const tempInput = document.createElement('input');
        tempInput.type = 'number';
        tempInput.id = 'param-temperature';
        tempInput.min = '0';
        tempInput.max = '2';
        tempInput.step = '0.1';
        tempInput.value = '0.7';
        tempItem.appendChild(tempLabel);
        tempItem.appendChild(tempInput);

        const tokensItem = document.createElement('div');
        tokensItem.className = 'params-item';
        const tokensLabel = document.createElement('label');
        tokensLabel.textContent = '最大上下文 (Max Tokens):';
        const tokensInput = document.createElement('input');
        tokensInput.type = 'number';
        tokensInput.id = 'param-max-tokens';
        tokensInput.min = '1';
        tokensInput.step = '1';
        tokensInput.value = '2048';
        tokensItem.appendChild(tokensLabel);
        tokensItem.appendChild(tokensInput);

        const memoryItem = document.createElement('div');
        memoryItem.className = 'params-item';
        const memoryLabel = document.createElement('label');
        memoryLabel.textContent = '记忆轮数:';
        const memoryInput = document.createElement('input');
        memoryInput.type = 'number';
        memoryInput.id = 'param-memory-rounds';
        memoryInput.min = '0';
        memoryInput.step = '1';
        memoryInput.value = '15';
        memoryInput.title = '设置为0表示不限制';
        memoryItem.appendChild(memoryLabel);
        memoryItem.appendChild(memoryInput);

        paramsPanel.appendChild(tempItem);
        paramsPanel.appendChild(tokensItem);
        paramsPanel.appendChild(memoryItem);

        inputArea.appendChild(inputWrapper);
        inputArea.appendChild(sendBtn);
        inputArea.appendChild(promptDropdown);
        inputArea.appendChild(paramsPanel);

        chatMain.appendChild(modelSelector);
        chatMain.appendChild(messages);
        chatMain.appendChild(inputArea);

        chatContainer.appendChild(conversationsSidebar);
        chatContainer.appendChild(chatMain);
        chatTab.appendChild(chatContainer);

        // 提供商标签页
        const providersTab = document.createElement('div');
        providersTab.className = 'tab-content';
        providersTab.id = 'providers-tab';
        const providersContainer = document.createElement('div');
        providersContainer.className = 'providers-container';
        const providersSidebar = document.createElement('div');
        providersSidebar.className = 'providers-sidebar';
        const addProviderBtn = document.createElement('button');
        addProviderBtn.id = 'add-provider-btn';
        addProviderBtn.textContent = '+ 添加供应商';
        const providersList = document.createElement('div');
        providersList.className = 'providers-list';
        providersList.id = 'providers-sidebar-list';
        providersSidebar.appendChild(addProviderBtn);
        providersSidebar.appendChild(providersList);
        const providerDetail = document.createElement('div');
        providerDetail.className = 'provider-detail';
        providerDetail.id = 'provider-detail';
        const emptyState = document.createElement('div');
        emptyState.className = 'empty-state';
        emptyState.textContent = '请选择或添加一个供应商';
        providerDetail.appendChild(emptyState);
        providersContainer.appendChild(providersSidebar);
        providersContainer.appendChild(providerDetail);
        providersTab.appendChild(providersContainer);

        // 提示词标签页
        const promptsTab = document.createElement('div');
        promptsTab.className = 'tab-content';
        promptsTab.id = 'prompts-tab';
        const promptsToolbar = document.createElement('div');
        promptsToolbar.className = 'prompts-toolbar';
        const addPromptBtn = document.createElement('button');
        addPromptBtn.id = 'add-prompt';
        addPromptBtn.textContent = '+ 新增';
        const batchDeleteBtn = document.createElement('button');
        batchDeleteBtn.id = 'batch-delete-prompt';
        batchDeleteBtn.textContent = '批量删除';
        promptsToolbar.appendChild(addPromptBtn);
        promptsToolbar.appendChild(batchDeleteBtn);
        const promptsList = document.createElement('div');
        promptsList.className = 'prompts-list';
        promptsList.id = 'prompts-list';
        promptsTab.appendChild(promptsToolbar);
        promptsTab.appendChild(promptsList);

        // 系统配置标签页
        const systemTab = document.createElement('div');
        systemTab.className = 'tab-content';
        systemTab.id = 'system-tab';
        const systemContainer = document.createElement('div');
        systemContainer.className = 'system-config-container';
        systemContainer.innerHTML = `
            <h3>系统配置</h3>
            <div class="config-section">
                <h4>新建对话默认设置</h4>
                <div class="form-group">
                    <label>默认模型</label>
                    <select id="default-model-select" class="config-select">
                        <option value="">未设置</option>
                    </select>
                </div>
                <div class="form-group">
                    <label>默认提示词</label>
                    <select id="default-prompt-select" class="config-select">
                        <option value="">未设置</option>
                    </select>
                </div>
                <button id="save-system-config" class="save-btn">保存配置</button>
            </div>
        `;
        systemTab.appendChild(systemContainer);

        content.appendChild(chatTab);
        content.appendChild(providersTab);
        content.appendChild(promptsTab);
        content.appendChild(systemTab);
        sidebar.appendChild(content);

        document.body.appendChild(sidebar);
        return sidebar;
    };

    // 创建触发按钮
    const createTriggerButton = () => {
        const btn = document.createElement('button');
        btn.id = 'ai-chat-trigger';
        btn.textContent = '💬';
        btn.title = 'AI对话';
        document.body.appendChild(btn);
        return btn;
    };

    // 添加样式
    const addStyles = () => {
        // 添加highlight.js样式
        const highlightStyle = document.createElement('link');
        highlightStyle.rel = 'stylesheet';
        highlightStyle.href = 'https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/github-dark.min.css';
        document.head.appendChild(highlightStyle);

        const style = document.createElement('style');
        style.textContent = `
            #ai-chat-trigger {
                position: fixed;
                right: 20px;
                bottom: 20px;
                width: 60px;
                height: 60px;
                border-radius: 50%;
                background: var(--ai-primaryGradient, linear-gradient(135deg, #667eea 0%, #764ba2 100%));
                border: none;
                color: white;
                font-size: 28px;
                cursor: pointer;
                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                z-index: 9998;
                transition: transform 0.2s;
            }
            #ai-chat-trigger:hover {
                transform: scale(1.1);
            }
            #ai-chat-sidebar {
                position: fixed;
                top: 0;
                right: 0;
                width: 400px;
                height: 100vh;
                background: var(--ai-bg, white);
                color: var(--ai-text, #333);
                box-shadow: var(--ai-shadowLg, -2px 0 8px rgba(0,0,0,0.1));
                z-index: 9999;
                display: none;
                flex-direction: column;
                border-radius: 0;
                font-family: var(--ai-fontFamily, inherit);
            }
            #ai-chat-sidebar.open {
                display: flex;
            }
            #ai-chat-sidebar.resizing, #ai-chat-sidebar.dragging {
                transition: none;
            }
            .resize-handle-left, .resize-handle-right {
                position: absolute;
                top: 0;
                width: 5px;
                height: 100%;
                cursor: ew-resize;
                z-index: 10;
            }
            .resize-handle-left {
                left: 0;
            }
            .resize-handle-right {
                right: 0;
            }
            .resize-handle-top, .resize-handle-bottom {
                position: absolute;
                left: 0;
                width: 100%;
                height: 5px;
                cursor: ns-resize;
                z-index: 10;
            }
            .resize-handle-top {
                top: 0;
            }
            .resize-handle-bottom {
                bottom: 0;
            }
            .resize-handle-corner-tl, .resize-handle-corner-tr,
            .resize-handle-corner-bl, .resize-handle-corner-br {
                position: absolute;
                width: 10px;
                height: 10px;
                z-index: 11;
            }
            .resize-handle-corner-tl {
                top: 0;
                left: 0;
                cursor: nwse-resize;
            }
            .resize-handle-corner-tr {
                top: 0;
                right: 0;
                cursor: nesw-resize;
            }
            .resize-handle-corner-bl {
                bottom: 0;
                left: 0;
                cursor: nesw-resize;
            }
            .resize-handle-corner-br {
                bottom: 0;
                right: 0;
                cursor: nwse-resize;
            }
            .sidebar-header {
                padding: 0 var(--ai-spacing, 15px);
                height: var(--ai-headerHeight, auto);
                min-height: 50px;
                background: var(--ai-primaryGradient, linear-gradient(135deg, #667eea 0%, #764ba2 100%));
                color: white;
                display: flex;
                gap: 10px;
                align-items: center;
                cursor: move;
                user-select: none;
                flex-wrap: wrap;
                font-weight: 600;
                transition: var(--ai-transition, all 0.2s ease);
            }
            .header-controls {
                display: flex;
                align-items: center;
                gap: 8px;
                margin-left: auto;
                position: relative;
            }
            .theme-btn {
                background: rgba(255,255,255,0.2);
                border: none;
                color: white;
                width: 28px;
                height: 28px;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                display: flex;
                align-items: center;
                justify-content: center;
                font-size: 14px;
                transition: background 0.2s;
            }
            .theme-btn:hover {
                background: rgba(255,255,255,0.3);
            }
            .theme-dropdown {
                position: absolute;
                top: 100%;
                right: 0;
                margin-top: 8px;
                background: var(--ai-bg, white);
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #ddd);
                border-radius: var(--ai-borderRadius, 4px);
                box-shadow: var(--ai-shadowLg, 0 2px 8px rgba(0,0,0,0.1));
                padding: 5px;
                display: none;
                z-index: 1000;
                min-width: 150px;
            }
            .theme-dropdown.show {
                display: block;
            }
            .theme-item {
                padding: 8px 12px;
                cursor: pointer;
                display: flex;
                align-items: center;
                gap: 8px;
                border-radius: var(--ai-borderRadius, 4px);
                color: var(--ai-text, #333);
                font-size: 13px;
            }
            .theme-item:hover {
                background: var(--ai-hover, #f5f5f5);
            }
            .theme-preview {
                width: 16px;
                height: 16px;
                border-radius: 50%;
                border: 1px solid rgba(0,0,0,0.1);
            }
            .tabs {
                display: flex;
                gap: 10px;
                flex-wrap: wrap;
                flex: 1;
            }
            .tab {
                background: transparent;
                border: none;
                color: inherit;
                padding: 8px 12px;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                transition: var(--ai-transition, all 0.2s ease);
                font-family: inherit;
                font-size: var(--ai-fontSize, 14px);
                font-weight: 500;
                opacity: 0.8;
            }
            .tab:hover {
                opacity: 1;
                background: rgba(255,255,255,0.1);
            }
            .tab.active {
                opacity: 1;
                background: rgba(255,255,255,0.2);
                font-weight: 600;
            }
            .close-btn {
                background: none;
                border: none;
                color: white;
                font-size: 28px;
                cursor: pointer;
                line-height: 1;
                padding: 0 5px;
            }
            .sidebar-content {
                flex: 1;
                overflow: hidden;
                display: flex;
                flex-direction: column;
                background: var(--ai-bg, white);
            }
            .tab-content {
                display: none;
                flex: 1;
                flex-direction: column;
                overflow: hidden;
            }
            .tab-content.active {
                display: flex;
            }
            .messages {
                flex: 1;
                overflow-y: auto;
                padding: 15px;
                display: flex;
                flex-direction: column;
                background: var(--ai-bg, white);
            }
            .message {
                margin-bottom: 25px;
                padding: 10px;
                border-radius: var(--ai-borderRadius, 8px);
                max-width: 80%;
                width: fit-content;
                text-align: left;
                position: relative;
                color: var(--ai-text, #333);
                border: var(--ai-borderWidth, 1px) solid transparent;
            }
            .message.user {
                background: var(--ai-userMsgBg, #667eea);
                color: var(--ai-userMsgText, white);
                align-self: flex-end;
                border-color: transparent;
            }
            .message.ai {
                background: var(--ai-aiMsgBg, #f0f0f0);
                color: var(--ai-aiMsgText, #333);
                align-self: flex-start;
                border-color: var(--ai-border, #ddd);
            }
            .message:hover .message-actions {
                opacity: 1;
            }
            .message.user {
                background: var(--ai-userMsgBg, #667eea);
                color: var(--ai-userMsgText, white);
                align-self: flex-end;
            }
            .message.ai {
                background: var(--ai-aiMsgBg, #f0f0f0);
                color: var(--ai-aiMsgText, #333);
                align-self: flex-start;
            }
            .message-actions {
                opacity: 0;
                position: absolute;
                bottom: -20px;
                display: flex;
                gap: 5px;
                transition: opacity 0.2s;
            }
            .message.user .message-actions {
                right: 0;
            }
            .message.ai .message-actions {
                left: 0;
            }
            .message-action-btn {
                background: var(--ai-bg, rgba(255,255,255,0.95));
                border: 1px solid var(--ai-border, #ddd);
                cursor: pointer;
                font-size: 12px;
                padding: 4px 8px;
                border-radius: var(--ai-btnRadius, 3px);
                transition: var(--ai-transition, all 0.2s ease);
                color: var(--ai-textSecondary, #666);
                display: flex;
                align-items: center;
                justify-content: center;
            }
            .message-action-btn:hover {
                background: var(--ai-hover, #f5f5f5);
                color: var(--ai-primary, #667eea);
                transform: scale(1.05);
            }
            #ai-chat-sidebar .message pre {
                background: #282c34;
                padding: 12px;
                border-radius: var(--ai-borderRadius, 6px);
                overflow-x: auto;
                margin: 8px 0;
            }
            #ai-chat-sidebar .message code {
                font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
                font-size: 13px;
            }
            #ai-chat-sidebar .message pre code {
                background: none;
                padding: 0;
            }
            #ai-chat-sidebar .message :not(pre) > code {
                background: var(--ai-hover, rgba(0,0,0,0.1));
                padding: 2px 6px;
                border-radius: var(--ai-btnRadius, 3px);
            }
            #ai-chat-sidebar .message p {
                margin: 8px 0;
            }
            #ai-chat-sidebar .message p:first-child {
                margin-top: 0;
            }
            #ai-chat-sidebar .message p:last-child {
                margin-bottom: 0;
            }
            #ai-chat-sidebar .message ul, #ai-chat-sidebar .message ol {
                margin: 8px 0;
                padding-left: 24px;
            }
            #ai-chat-sidebar .message blockquote {
                border-left: 3px solid var(--ai-primary, #667eea);
                padding-left: 12px;
                margin: 8px 0;
                color: var(--ai-textSecondary, #666);
            }
            #ai-chat-sidebar .message table {
                border-collapse: collapse;
                margin: 8px 0;
                width: 100%;
            }
            #ai-chat-sidebar .message th, #ai-chat-sidebar .message td {
                border: 1px solid var(--ai-border, #ddd);
                padding: 8px;
                text-align: left;
            }
            #ai-chat-sidebar .message th {
                background: var(--ai-bgSecondary, #f5f5f5);
                font-weight: bold;
            }
            .thinking-section {
                margin: 8px 0;
                border: 1px solid var(--ai-border, #ddd);
                border-radius: var(--ai-borderRadius, 4px);
                overflow: hidden;
            }
            .thinking-header {
                background: var(--ai-bgSecondary, #f5f5f5);
                padding: 8px 12px;
                cursor: pointer;
                display: flex;
                align-items: center;
                gap: 8px;
                user-select: none;
                color: var(--ai-text, #333);
            }
            .thinking-header:hover {
                background: var(--ai-hover, #e8e8e8);
            }
            .thinking-toggle {
                font-size: 12px;
                transition: transform 0.2s;
            }
            .thinking-toggle.collapsed {
                transform: rotate(-90deg);
            }
            .thinking-content {
                padding: 12px;
                background: var(--ai-bgSecondary, #fafafa);
                border-top: 1px solid var(--ai-border, #ddd);
                max-height: 300px;
                overflow-y: auto;
                color: var(--ai-text, #333);
            }
            .thinking-content.collapsed {
                display: none;
            }
            .model-selector {
                padding: 10px var(--ai-spacing, 15px);
                border-bottom: var(--ai-borderWidth, 1px) solid var(--ai-border, #eee);
                position: relative;
                background: var(--ai-bg, white);
                transition: var(--ai-transition, all 0.2s ease);
            }
            #model-display-btn {
                background: none;
                border: none;
                color: var(--ai-primary, #667eea);
                font-size: var(--ai-fontSize, 14px);
                cursor: pointer;
                display: flex;
                align-items: center;
                gap: 5px;
                padding: 5px 0;
                font-weight: 600;
                font-family: inherit;
            }
            #model-display-btn:hover {
                opacity: 0.8;
            }
            #model-display-btn .arrow {
                font-size: 10px;
                transition: transform 0.2s;
            }
            #model-display-btn.open .arrow {
                transform: rotate(180deg);
            }
            .model-dropdown {
                position: absolute;
                top: 100%;
                left: var(--ai-spacing, 15px);
                right: var(--ai-spacing, 15px);
                background: var(--ai-bg, white);
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #ddd);
                border-radius: var(--ai-borderRadius, 4px);
                box-shadow: var(--ai-shadowLg, 0 2px 8px rgba(0,0,0,0.1));
                max-height: 200px;
                overflow-y: auto;
                z-index: 100;
                margin-top: 5px;
            }
            .model-dropdown-item {
                padding: 10px var(--ai-spacing, 15px);
                cursor: pointer;
                border-bottom: var(--ai-borderWidth, 1px) solid var(--ai-border, #f0f0f0);
                color: var(--ai-text, #333);
                font-size: var(--ai-fontSize, 14px);
                transition: var(--ai-transition, all 0.2s ease);
            }
            .model-dropdown-item:last-child {
                border-bottom: none;
            }
            .model-dropdown-item:hover {
                background: var(--ai-hover, #f5f5f5);
            }
            .model-dropdown-item.selected {
                background: var(--ai-primary, #667eea);
                color: white;
            }
            .input-area {
                padding: var(--ai-spacing, 15px);
                border-top: var(--ai-borderWidth, 1px) solid var(--ai-border, #eee);
                position: relative;
                background: var(--ai-bg, white);
                transition: var(--ai-transition, all 0.2s ease);
            }
            .input-wrapper {
                position: relative;
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #ddd);
                border-radius: var(--ai-borderRadius, 4px);
                background: var(--ai-bg, white);
                padding: 12px;
                display: flex;
                flex-direction: column;
                gap: 8px;
                resize: vertical;
                overflow: hidden;
                min-height: 80px;
                transition: var(--ai-transition, all 0.2s ease);
                box-shadow: 0 2px 6px rgba(0,0,0,0.02);
            }
            .input-wrapper:focus-within {
                border-color: var(--ai-primary, #667eea);
                box-shadow: 0 0 0 2px var(--ai-shadow, rgba(102, 126, 234, 0.1));
            }
            .prompt-icon-top {
                background: none;
                border: none;
                font-size: 18px;
                cursor: pointer;
                padding: 4px;
                align-self: flex-start;
                line-height: 1;
                border-radius: 4px;
                transition: background 0.2s;
                flex-shrink: 0;
            }
            .prompt-icon-top:hover {
                background: rgba(102, 126, 234, 0.1);
            }
            .prompt-icon-top.selected {
                background: rgba(102, 126, 234, 0.2);
            }
            #user-input {
                flex: 1;
                border: none;
                outline: none;
                resize: none;
                font-family: inherit;
                min-height: 40px;
                padding: 0;
                overflow-y: auto;
                background: var(--ai-bg, white);
                color: var(--ai-text, #333);
            }
            #send-btn {
                margin-top: 10px;
            }
            .prompt-dropdown {
                position: absolute;
                bottom: 100%;
                left: 0;
                right: 0;
                background: var(--ai-bg, white);
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #ddd);
                border-radius: var(--ai-borderRadius, 4px);
                box-shadow: var(--ai-shadowLg, 0 -2px 8px rgba(0,0,0,0.1));
                max-height: 300px;
                overflow-y: auto;
                z-index: 100;
                margin-bottom: 8px;
            }
            .prompt-dropdown-item {
                padding: 10px var(--ai-spacing, 15px);
                cursor: pointer;
                border-bottom: var(--ai-borderWidth, 1px) solid var(--ai-border, #f0f0f0);
                color: var(--ai-text, #333);
                transition: var(--ai-transition, all 0.2s ease);
            }
            .prompt-dropdown-item:last-child {
                border-bottom: none;
            }
            .prompt-dropdown-item:hover {
                background: var(--ai-hover, #f5f5f5);
            }
            .prompt-dropdown-item .prompt-title {
                font-weight: 600;
                margin-bottom: 4px;
                font-size: var(--ai-fontSize, 14px);
            }
            .prompt-dropdown-item .prompt-preview {
                font-size: 12px;
                color: var(--ai-textSecondary, #999);
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }
            .params-panel {
                position: absolute;
                bottom: 100%;
                left: 0;
                right: 0;
                background: var(--ai-bg, white);
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #ddd);
                border-radius: var(--ai-borderRadius, 4px);
                box-shadow: var(--ai-shadowLg, 0 -2px 8px rgba(0,0,0,0.1));
                padding: var(--ai-spacing, 15px);
                z-index: 100;
                margin-bottom: 8px;
            }
            .params-item {
                margin-bottom: 10px;
            }
            .params-item:last-child {
                margin-bottom: 0;
            }
            .params-item label {
                display: block;
                margin-bottom: 5px;
                font-size: 12px;
                font-weight: 500;
                color: var(--ai-text, #333);
            }
            .params-item input {
                width: 100%;
                padding: 6px;
                border: 1px solid var(--ai-border, #ddd);
                border-radius: 4px;
                font-size: 13px;
                background: var(--ai-bg, white);
                color: var(--ai-text, #333);
            }
            #send-btn {
                padding: 10px 24px;
                background: var(--ai-primary, #667eea);
                color: white;
                border: none;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                font-weight: 600;
                font-size: 14px;
                transition: var(--ai-transition, all 0.2s ease);
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            }
            #send-btn:hover {
                opacity: 0.9;
                transform: translateY(-1px);
                box-shadow: 0 4px 8px rgba(0,0,0,0.15);
            }
            #send-btn:active {
                transform: translateY(0);
            }
            .chat-container {
                display: flex;
                height: 100%;
            }
            .conversations-sidebar {
                width: 200px;
                border-right: var(--ai-borderWidth, 1px) solid var(--ai-border, #eee);
                display: flex;
                flex-direction: column;
                background: var(--ai-bgSecondary, #fafafa);
                transition: var(--ai-transition, all 0.2s ease);
            }
            .conversations-toolbar {
                padding: 10px;
                border-bottom: var(--ai-borderWidth, 1px) solid var(--ai-border, #eee);
                display: flex;
                gap: 5px;
            }
            .conversations-toolbar button {
                flex: 1;
                padding: 6px;
                border: none;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                font-size: 12px;
                color: white;
                font-family: inherit;
                transition: var(--ai-transition, all 0.2s ease);
            }
            .batch-delete-conv-btn {
                background: #e74c3c;
            }
            .batch-delete-conv-btn:hover {
                opacity: 0.9;
            }
            .conversations-list {
                flex: 1;
                overflow-y: auto;
            }
            .conversation-item {
                padding: 10px 12px;
                cursor: pointer;
                border-bottom: var(--ai-borderWidth, 1px) solid var(--ai-border, #eee);
                transition: background 0.2s;
                font-size: 13px;
                display: flex;
                align-items: center;
                gap: 8px;
                position: relative;
                color: var(--ai-text, #333);
            }
            .conversation-item input[type="checkbox"] {
                width: 16px;
                height: 16px;
                cursor: pointer;
                flex-shrink: 0;
            }
            .conversation-item .conv-title {
                flex: 1;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }
            .conversation-item .conv-actions {
                display: none;
                gap: 4px;
                flex-shrink: 0;
            }
            .conversation-item:hover .conv-actions {
                display: flex;
            }
            .conversation-item .conv-action-btn {
                padding: 2px 6px;
                background: rgba(0,0,0,0.1);
                border: none;
                border-radius: 3px;
                cursor: pointer;
                font-size: 12px;
            }
            .conversation-item .conv-action-btn:hover {
                background: rgba(0,0,0,0.2);
            }
            .conversation-item:hover {
                background: var(--ai-hover, #f0f0f0);
            }
            .conversation-item.active {
                background: var(--ai-primary, #667eea);
                color: white;
            }
            .conversation-item.active .conv-action-btn {
                background: rgba(255,255,255,0.2);
            }
            .conversation-item.active .conv-action-btn:hover {
                background: rgba(255,255,255,0.3);
            }
            .conversation-item.editing .conv-title {
                display: none;
            }
            .conversation-item .conv-rename-input {
                display: none;
                flex: 1;
                padding: 4px;
                border: 1px solid var(--ai-border, #ddd);
                border-radius: 3px;
                font-size: 12px;
                background: var(--ai-bg, white);
                color: var(--ai-text, #333);
            }
            .conversation-item.editing .conv-rename-input {
                display: block;
            }
            .chat-main {
                flex: 1;
                display: flex;
                flex-direction: column;
                overflow: hidden;
                background: var(--ai-bg, white);
            }
            .providers-container {
                display: flex;
                height: 100%;
                background: var(--ai-bg, white);
            }
            .providers-sidebar {
                width: 200px;
                border-right: var(--ai-borderWidth, 1px) solid var(--ai-border, #eee);
                display: flex;
                flex-direction: column;
                background: var(--ai-bgSecondary, #fafafa);
            }
            #add-provider-btn {
                margin: 15px;
                padding: 10px;
                background: var(--ai-primary, #667eea);
                color: white;
                border: none;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                font-weight: 600;
                transition: var(--ai-transition, all 0.2s ease);
            }
            #add-provider-btn:hover {
                opacity: 0.9;
                transform: translateY(-1px);
            }
            .providers-list {
                flex: 1;
                overflow-y: auto;
            }
            .provider-sidebar-item {
                padding: 12px 15px;
                cursor: pointer;
                border-bottom: var(--ai-borderWidth, 1px) solid var(--ai-border, #eee);
                transition: background 0.2s;
                display: flex;
                align-items: center;
                justify-content: space-between;
                color: var(--ai-text, #333);
            }
            .provider-sidebar-item:hover {
                background: var(--ai-hover, #f5f5f5);
            }
            .provider-sidebar-item.active {
                background: var(--ai-primary, #667eea);
                color: white;
            }
            .provider-sidebar-item .delete-icon {
                opacity: 0;
                cursor: pointer;
                font-size: 16px;
                padding: 2px 6px;
                border-radius: 3px;
                transition: opacity 0.2s;
            }
            .provider-sidebar-item:hover .delete-icon {
                opacity: 1;
            }
            .provider-sidebar-item .delete-icon:hover {
                background: rgba(231, 76, 60, 0.2);
            }
            .provider-sidebar-item.active .delete-icon:hover {
                background: rgba(255, 255, 255, 0.3);
            }
            .provider-detail {
                flex: 1;
                overflow-y: auto;
                padding: 20px;
                color: var(--ai-text, #333);
            }
            .empty-state {
                text-align: center;
                color: var(--ai-textSecondary, #999);
                padding: 50px 20px;
            }
            .provider-form {
                max-width: 600px;
            }
            .provider-form h3 {
                margin: 0 0 20px 0;
            }
            .form-group {
                margin-bottom: 15px;
                display: flex;
                align-items: center;
                gap: 15px;
            }
            .form-group label {
                min-width: 100px;
                font-weight: bold;
            }
            .form-group input {
                flex: 1;
                padding: 8px;
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #ddd);
                border-radius: var(--ai-borderRadius, 4px);
                background: var(--ai-bg, white);
                color: var(--ai-text, #333);
            }
            .final-url-display {
                margin-left: 115px;
                padding: 8px;
                background: var(--ai-bgSecondary, #f0f0f0);
                border-radius: 4px;
                font-size: 12px;
                color: var(--ai-textSecondary, #666);
                word-break: break-all;
            }
            .final-url-display strong {
                color: var(--ai-text, #333);
            }
            .form-group.password-group {
                position: relative;
            }
            .form-group.password-group input {
                padding-right: 40px;
            }
            .form-group .toggle-password {
                position: absolute;
                right: 10px;
                cursor: pointer;
                font-size: 18px;
                user-select: none;
            }
            .form-actions {
                display: flex;
                gap: 10px;
                margin-top: 20px;
                margin-left: 115px;
            }
            .form-actions button {
                padding: 10px 20px;
                border: none;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                color: white;
            }
            .save-provider-btn {
                background: var(--ai-primary, #667eea);
            }
            .models-section {
                margin-top: 30px;
                padding-top: 20px;
                border-top: calc(var(--ai-borderWidth, 1px) * 2) solid var(--ai-border, #eee);
            }
            .models-section h3 {
                margin: 0 0 15px 0;
                display: flex;
                align-items: center;
                gap: 10px;
                color: var(--ai-text, #333);
            }
            .fetch-models-btn, .refresh-models-btn {
                padding: 6px 12px;
                background: #3498db;
                color: white;
                border: none;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                font-size: 12px;
                transition: var(--ai-transition, all 0.2s ease);
            }
            .fetch-models-btn:hover, .refresh-models-btn:hover {
                opacity: 0.9;
            }
            .refresh-models-btn {
                background: #2ecc71;
            }
            .available-models-section {
                margin-top: 20px;
                padding: 15px;
                background: var(--ai-bgSecondary, #f9f9f9);
                border-radius: var(--ai-borderRadius, 8px);
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #eee);
            }
            .available-models-section h4 {
                margin: 0 0 10px 0;
                font-size: 14px;
            }
            .model-search {
                width: 100%;
                padding: 8px;
                margin-bottom: 10px;
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #ddd);
                border-radius: var(--ai-borderRadius, 4px);
                background: var(--ai-bg, white);
                color: var(--ai-text, #333);
            }
            .available-models-list {
                max-height: 300px;
                overflow-y: auto;
                display: flex;
                flex-direction: column;
                gap: 5px;
            }
            .available-model-item {
                display: flex;
                align-items: center;
                justify-content: space-between;
                padding: 8px;
                background: var(--ai-bg, white);
                border-radius: var(--ai-borderRadius, 4px);
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #eee);
            }
            .available-model-item .model-name {
                flex: 1;
                font-size: 13px;
            }
            .available-model-item .add-model-icon {
                cursor: pointer;
                color: var(--ai-primary, #667eea);
                font-size: 18px;
                padding: 2px 6px;
                border-radius: 3px;
                transition: background 0.2s;
            }
            .available-model-item .add-model-icon:hover {
                background: rgba(102, 126, 234, 0.1);
            }
            .loading-models {
                text-align: center;
                padding: 20px;
                color: var(--ai-textSecondary, #999);
            }
            .models-list {
                display: flex;
                flex-direction: column;
                gap: 10px;
            }
            .model-item {
                background: var(--ai-bgSecondary, #f9f9f9);
                padding: 10px;
                border-radius: var(--ai-borderRadius, 4px);
                display: flex;
                align-items: center;
                gap: 10px;
            }
            .model-item input {
                flex: 1;
                padding: 8px;
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #ddd);
                border-radius: var(--ai-borderRadius, 4px);
                background: var(--ai-bg, white);
                color: var(--ai-text, #333);
            }
            .model-item button {
                padding: 6px 12px;
                border: none;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                font-size: 12px;
                color: white;
            }
            .save-model-btn {
                background: var(--ai-primary, #667eea);
            }
            .delete-model-btn {
                background: #e74c3c;
            }
            .add-model-btn {
                margin-top: 10px;
                padding: 8px 16px;
                background: var(--ai-primary, #667eea);
                color: white;
                border: none;
                border-radius: 4px;
                cursor: pointer;
            }
            .prompts-toolbar {
                padding: var(--ai-spacing, 15px);
                display: flex;
                gap: 10px;
                border-bottom: var(--ai-borderWidth, 1px) solid var(--ai-border, #eee);
                background: var(--ai-bg, white);
            }
            .prompts-toolbar button {
                padding: 8px 16px;
                border: none;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                color: white;
                font-weight: 600;
                transition: var(--ai-transition, all 0.2s ease);
            }
            .prompts-toolbar button:hover {
                opacity: 0.9;
                transform: translateY(-1px);
            }
            #add-prompt {
                background: var(--ai-primary, #667eea);
            }
            #batch-delete-prompt {
                background: #e74c3c;
            }
            .prompts-list {
                flex: 1;
                overflow-y: auto;
                padding: 15px;
                background: var(--ai-bg, white);
            }
            .prompt-item {
                background: var(--ai-bgSecondary, #f9f9f9);
                padding: 15px;
                margin-bottom: 10px;
                border-radius: var(--ai-borderRadius, 8px);
                position: relative;
                color: var(--ai-text, #333);
            }
            .prompt-item.editing {
                background: var(--ai-bg, #fff);
                border: 2px solid var(--ai-primary, #667eea);
            }
            .prompt-item input[type="checkbox"] {
                position: absolute;
                top: 15px;
                left: 15px;
                width: 18px;
                height: 18px;
                cursor: pointer;
            }
            .prompt-item .prompt-header {
                display: flex;
                align-items: center;
                gap: 10px;
                margin-bottom: 10px;
                padding-left: 30px;
            }
            .prompt-item .prompt-title {
                flex: 1;
                font-weight: bold;
                font-size: 16px;
            }
            .prompt-item .prompt-actions {
                display: flex;
                gap: 5px;
            }
            .prompt-item .prompt-actions button {
                padding: 4px 10px;
                border: none;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                font-size: 12px;
            }
            .prompt-item .view-btn {
                background: #3498db;
                color: white;
            }
            .prompt-item .edit-btn {
                background: #f39c12;
                color: white;
            }
            .prompt-item .delete-btn {
                background: #e74c3c;
                color: white;
            }
            .prompt-item .prompt-content {
                padding-left: 30px;
                color: var(--ai-textSecondary, #666);
                white-space: pre-wrap;
                word-break: break-word;
            }
            .prompt-item .prompt-form {
                padding-left: 30px;
            }
            .prompt-item .prompt-form input,
            .prompt-item .prompt-form textarea {
                width: 100%;
                padding: 8px;
                margin: 5px 0;
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #ddd);
                border-radius: var(--ai-borderRadius, 4px);
                font-family: inherit;
                background: var(--ai-bg, white);
                color: var(--ai-text, #333);
            }
            .prompt-item .prompt-form textarea {
                min-height: 100px;
                resize: vertical;
            }
            .prompt-item .prompt-form .form-actions {
                margin-top: 10px;
                display: flex;
                gap: 10px;
            }
            .prompt-item .prompt-form .form-actions button {
                padding: 6px 16px;
                border: none;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                color: white;
            }
            .prompt-item .save-prompt-btn {
                background: var(--ai-primary, #667eea);
            }
            .prompt-item .cancel-btn {
                background: #95a5a6;
            }
            
            .system-config-container {
                padding: 20px;
                color: var(--ai-text, #333);
            }
            .system-config-container h3 {
                margin: 0 0 20px 0;
            }
            .config-section {
                background: var(--ai-bgSecondary, #f9f9f9);
                padding: 20px;
                border-radius: var(--ai-borderRadius, 8px);
                margin-bottom: 20px;
            }
            .config-section h4 {
                margin: 0 0 15px 0;
                font-size: 16px;
            }
            .config-select {
                width: 100%;
                padding: 8px;
                border: var(--ai-borderWidth, 1px) solid var(--ai-border, #ddd);
                border-radius: var(--ai-borderRadius, 4px);
                background: var(--ai-bg, white);
                color: var(--ai-text, #333);
                font-size: 14px;
            }
            .save-btn {
                margin-top: 15px;
                padding: 10px 20px;
                background: var(--ai-primary, #667eea);
                color: white;
                border: none;
                border-radius: var(--ai-btnRadius, 4px);
                cursor: pointer;
                font-weight: 600;
            }
            .save-btn:hover {
                opacity: 0.9;
            }
            
            /* Scrollbar Styling */
            #ai-chat-sidebar ::-webkit-scrollbar {
                width: 6px;
                height: 6px;
            }
            #ai-chat-sidebar ::-webkit-scrollbar-track {
                background: transparent;
            }
            #ai-chat-sidebar ::-webkit-scrollbar-thumb {
                background: var(--ai-border, rgba(0, 0, 0, 0.1));
                border-radius: 3px;
            }
            #ai-chat-sidebar ::-webkit-scrollbar-thumb:hover {
                background: var(--ai-textSecondary, rgba(0, 0, 0, 0.2));
            }
        `;
        document.head.appendChild(style);
    };

    // 初始化
    const init = () => {
        addStyles();
        const triggerBtn = createTriggerButton();
        const sidebar = createSidebar();

        // 切换侧边栏
        triggerBtn.addEventListener('click', () => {
            sidebar.classList.toggle('open');
        });

        sidebar.querySelector('.close-btn').addEventListener('click', () => {
            sidebar.classList.remove('open');
        });

        // 主题切换
        const themeBtn = sidebar.querySelector('.theme-btn');
        const themeDropdown = sidebar.querySelector('.theme-dropdown');
        
        themeBtn.addEventListener('click', (e) => {
            e.stopPropagation();
            themeDropdown.classList.toggle('show');
        });
        
        themeDropdown.addEventListener('click', (e) => {
            const item = e.target.closest('.theme-item');
            if (!item) return;
            
            const themeName = item.dataset.theme;
            applyTheme(themeName);
            themeDropdown.classList.remove('show');
        });
        
        document.addEventListener('click', (e) => {
            if (!e.target.closest('.header-controls')) {
                themeDropdown.classList.remove('show');
            }
        });

        // 初始化主题
        applyTheme(ConfigManager.getTheme());

        // 拖拽调整大小
        let isResizing = false;
        let resizeType = '';
        let startX = 0;
        let startY = 0;
        let startWidth = 0;
        let startHeight = 0;
        let startLeft = 0;
        let startTop = 0;

        const startResize = (e, type) => {
            isResizing = true;
            resizeType = type;
            startX = e.clientX;
            startY = e.clientY;
            const rect = sidebar.getBoundingClientRect();
            startWidth = rect.width;
            startHeight = rect.height;
            startLeft = rect.left;
            startTop = rect.top;
            sidebar.classList.add('resizing');
            e.preventDefault();
            e.stopPropagation();
        };

        sidebar.querySelector('.resize-handle-left').addEventListener('mousedown', (e) => startResize(e, 'left'));
        sidebar.querySelector('.resize-handle-right').addEventListener('mousedown', (e) => startResize(e, 'right'));
        sidebar.querySelector('.resize-handle-top').addEventListener('mousedown', (e) => startResize(e, 'top'));
        sidebar.querySelector('.resize-handle-bottom').addEventListener('mousedown', (e) => startResize(e, 'bottom'));
        sidebar.querySelector('.resize-handle-corner-tl').addEventListener('mousedown', (e) => startResize(e, 'top-left'));
        sidebar.querySelector('.resize-handle-corner-tr').addEventListener('mousedown', (e) => startResize(e, 'top-right'));
        sidebar.querySelector('.resize-handle-corner-bl').addEventListener('mousedown', (e) => startResize(e, 'bottom-left'));
        sidebar.querySelector('.resize-handle-corner-br').addEventListener('mousedown', (e) => startResize(e, 'bottom-right'));

        document.addEventListener('mousemove', (e) => {
            if (!isResizing) return;

            const deltaX = e.clientX - startX;
            const deltaY = e.clientY - startY;

            if (resizeType.includes('left')) {
                const newWidth = startWidth - deltaX;
                if (newWidth >= 200) {
                    sidebar.style.width = newWidth + 'px';
                }
            }
            if (resizeType.includes('right')) {
                const newWidth = startWidth + deltaX;
                if (newWidth >= 200) {
                    sidebar.style.width = newWidth + 'px';
                }
            }
            if (resizeType.includes('top')) {
                const newHeight = startHeight - deltaY;
                if (newHeight >= 200) {
                    sidebar.style.height = newHeight + 'px';
                    sidebar.style.top = (startTop + deltaY) + 'px';
                }
            }
            if (resizeType.includes('bottom')) {
                const newHeight = startHeight + deltaY;
                if (newHeight >= 200) {
                    sidebar.style.height = newHeight + 'px';
                }
            }
        });

        document.addEventListener('mouseup', () => {
            if (isResizing) {
                isResizing = false;
                resizeType = '';
                sidebar.classList.remove('resizing');
            }
        });

        // 拖拽移动窗口
        const header = sidebar.querySelector('.sidebar-header');
        let isDragging = false;
        let dragStartX = 0;
        let dragStartY = 0;
        let sidebarLeft = 0;
        let sidebarTop = 0;

        header.addEventListener('mousedown', (e) => {
            // 如果点击的是按钮,不触发拖动
            if (e.target.tagName === 'BUTTON') return;
            isDragging = true;
            dragStartX = e.clientX;
            dragStartY = e.clientY;
            const rect = sidebar.getBoundingClientRect();
            sidebarLeft = rect.left;
            sidebarTop = rect.top;
            sidebar.classList.add('dragging');
            e.preventDefault();
        });

        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;
            const deltaX = e.clientX - dragStartX;
            const deltaY = e.clientY - dragStartY;
            const newLeft = sidebarLeft + deltaX;
            const newTop = sidebarTop + deltaY;
            sidebar.style.left = newLeft + 'px';
            sidebar.style.top = newTop + 'px';
        });

        document.addEventListener('mouseup', () => {
            if (isDragging) {
                isDragging = false;
                sidebar.classList.remove('dragging');
            }
        });

        // 选项卡切换
        sidebar.querySelectorAll('.tab').forEach(tab => {
            tab.addEventListener('click', () => {
                const tabName = tab.dataset.tab;
                sidebar.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
                sidebar.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
                tab.classList.add('active');
                sidebar.querySelector(`#${tabName}-tab`).classList.add('active');
            });
        });

        // AI提供商管理
        let currentProviderIndex = null;

        const renderProvidersSidebar = () => {
            const providers = ConfigManager.getProviders();
            const list = sidebar.querySelector('#providers-sidebar-list');
            list.textContent = '';

            providers.forEach((provider, index) => {
                const item = document.createElement('div');
                item.className = 'provider-sidebar-item';
                if (index === currentProviderIndex) {
                    item.classList.add('active');
                }
                safeInnerHTML(item, `
                    <span class="provider-name">${provider.name || '未命名供应商'}</span>
                    <span class="delete-icon" data-index="${index}">×</span>
                `);
                item.dataset.index = index;
                list.appendChild(item);
            });

            updateModelSelect();
        };

        const normalizeApiUrl = (url) => {
            if (!url) return '';
            url = url.trim();

            // 如果已经包含 /chat/completions,直接返回
            if (url.includes('/chat/completions')) {
                return url;
            }

            // 移除末尾的斜杠
            url = url.replace(/\/+$/, '');

            // 如果包含版本号(v1, v2, v3等),在其后添加 /chat/completions
            if (/\/v\d+$/i.test(url)) {
                return url + '/chat/completions';
            }

            // 默认添加 /v1/chat/completions
            return url + '/v1/chat/completions';
        };

        const getModelsUrl = (url) => {
            if (!url) return '';
            url = url.trim();

            // 如果已经包含 /models,直接返回
            if (url.includes('/models')) {
                return url;
            }

            // 移除末尾的斜杠
            url = url.replace(/\/+$/, '');

            // 如果包含版本号(v1, v2, v3等),在其后添加 /models
            if (/\/v\d+$/i.test(url)) {
                return url + '/models';
            }

            // 默认添加 /v1/models
            return url + '/v1/models';
        };

        const updateFinalUrl = (index) => {
            const urlInput = sidebar.querySelector(`#provider-url-${index}`);
            const finalUrlDisplay = sidebar.querySelector(`#final-url-${index}`);
            if (urlInput && finalUrlDisplay) {
                const finalUrl = normalizeApiUrl(urlInput.value);
                safeInnerHTML(finalUrlDisplay, `<strong>最终调用地址:</strong>${finalUrl || '请输入API URL'}`);
            }
        };

        const renderProviderDetail = (index) => {
            const providers = ConfigManager.getProviders();
            const provider = providers[index];
            const detail = sidebar.querySelector('#provider-detail');
            const models = ConfigManager.getModels(index);

            safeInnerHTML(detail, `
                <div class="provider-form">
                    <h3>供应商信息</h3>
                    <div class="form-group">
                        <label>供应商名称</label>
                        <input type="text" value="${provider.name || ''}" id="provider-name-${index}">
                    </div>
                    <div class="form-group">
                        <label>API URL</label>
                        <input type="text" value="${provider.url || ''}" id="provider-url-${index}" placeholder="例如: https://api.openai.com">
                    </div>
                    <div class="final-url-display" id="final-url-${index}"></div>
                    <div class="form-group password-group">
                        <label>API Key</label>
                        <input type="password" value="${provider.key || ''}" id="provider-key-${index}">
                        <span class="toggle-password" data-target="provider-key-${index}">👁️</span>
                    </div>
                    <div class="form-actions">
                        <button class="save-provider-btn" data-index="${index}">保存</button>
                    </div>

                    <div class="models-section">
                        <h3>
                            已添加模型
                            <button class="fetch-models-btn" data-index="${index}">获取模型列表</button>
                            <button class="refresh-models-btn" data-index="${index}" style="display:none;">刷新</button>
                        </h3>
                        <div class="models-list" id="models-list-${index}"></div>
                        <button class="add-model-btn" data-index="${index}">+ 手动添加模型</button>

                        <div class="available-models-section" id="available-models-${index}" style="display:none;">
                            <h4>可用模型列表</h4>
                            <input type="text" class="model-search" placeholder="搜索模型..." id="model-search-${index}">
                            <div class="available-models-list" id="available-models-list-${index}"></div>
                        </div>
                    </div>
                </div>
            `);

            const modelsList = detail.querySelector(`#models-list-${index}`);
            models.forEach((model, modelIndex) => {
                const item = document.createElement('div');
                item.className = 'model-item';
                safeInnerHTML(item, `
                    <input type="text" value="${model}" data-model="${modelIndex}">
                    <button class="save-model-btn" data-provider="${index}" data-model="${modelIndex}">保存</button>
                    <button class="delete-model-btn" data-provider="${index}" data-model="${modelIndex}">删除</button>
                `);
                modelsList.appendChild(item);
            });

            // 初始化显示最终URL
            updateFinalUrl(index);

            // 监听URL输入框变化
            const urlInput = sidebar.querySelector(`#provider-url-${index}`);
            if (urlInput) {
                urlInput.addEventListener('input', () => updateFinalUrl(index));
            }

            // 监听模型搜索
            const searchInput = detail.querySelector(`#model-search-${index}`);
            if (searchInput) {
                searchInput.addEventListener('input', (e) => {
                    filterAvailableModels(index, e.target.value);
                });
            }

            // 加载已保存的可用模型列表
            loadAvailableModels(index);
        };

        const fetchAvailableModels = async (index) => {
            const providers = ConfigManager.getProviders();
            const provider = providers[index];

            if (!provider.url || !provider.key) {
                alert('请先配置API URL和API Key');
                return;
            }

            const availableSection = sidebar.querySelector(`#available-models-${index}`);
            const availableList = sidebar.querySelector(`#available-models-list-${index}`);
            const fetchBtn = sidebar.querySelector(`.fetch-models-btn[data-index="${index}"]`);
            const refreshBtn = sidebar.querySelector(`.refresh-models-btn[data-index="${index}"]`);

            safeInnerHTML(availableList, '<div class="loading-models">正在获取模型列表...</div>');
            availableSection.style.display = 'block';

            const modelsUrl = getModelsUrl(provider.url);

            GM_xmlhttpRequest({
                method: 'GET',
                url: modelsUrl,
                headers: {
                    'Authorization': `Bearer ${provider.key}`
                },
                onload: (response) => {
                    try {
                        const data = JSON.parse(response.responseText);
                        const models = data.data || data.models || [];
                        const modelNames = models.map(m => m.id || m.name || m).filter(Boolean);

                        ConfigManager.saveAvailableModels(index, modelNames);
                        renderAvailableModels(index, modelNames);

                        fetchBtn.style.display = 'none';
                        refreshBtn.style.display = 'inline-block';
                    } catch (e) {
                        safeInnerHTML(availableList, '<div class="loading-models">获取失败: ' + e.message + '</div>');
                    }
                },
                onerror: () => {
                    safeInnerHTML(availableList, '<div class="loading-models">请求失败,请检查URL和API Key</div>');
                }
            });
        };

        const renderAvailableModels = (index, models) => {
            const availableList = sidebar.querySelector(`#available-models-list-${index}`);
            const existingModels = ConfigManager.getModels(index);

            availableList.textContent = '';
            models.forEach(modelName => {
                const item = document.createElement('div');
                item.className = 'available-model-item';
                item.dataset.modelName = modelName;
                safeInnerHTML(item, `
                    <span class="model-name">${modelName}</span>
                    <span class="add-model-icon" data-provider="${index}" data-model-name="${modelName}">+</span>
                `);
                availableList.appendChild(item);
            });
        };

        const filterAvailableModels = (index, keyword) => {
            const models = ConfigManager.getAvailableModels(index);
            const filtered = keyword ? models.filter(m => m.toLowerCase().includes(keyword.toLowerCase())) : models;
            renderAvailableModels(index, filtered);
        };

        const updateModelSelect = () => {
            // 保持兼容性,但不再使用
        };

        sidebar.querySelector('#add-provider-btn').addEventListener('click', () => {
            const providers = ConfigManager.getProviders();
            providers.push({name: '新供应商', url: '', key: ''});
            ConfigManager.saveProviders(providers);
            currentProviderIndex = providers.length - 1;
            renderProvidersSidebar();
            renderProviderDetail(currentProviderIndex);
        });

        sidebar.querySelector('#providers-sidebar-list').addEventListener('click', (e) => {
            if (e.target.classList.contains('delete-icon')) {
                e.stopPropagation();
                const index = parseInt(e.target.dataset.index);
                if (!confirm('确定删除此供应商吗?')) return;

                const providers = ConfigManager.getProviders();
                providers.splice(index, 1);
                ConfigManager.saveProviders(providers);

                if (currentProviderIndex === index) {
                    currentProviderIndex = null;
                    safeInnerHTML(sidebar.querySelector('#provider-detail'), '<div class="empty-state">请选择或添加一个供应商</div>');
                } else if (currentProviderIndex > index) {
                    currentProviderIndex--;
                }
                renderProvidersSidebar();
                updateModelSelect();
                return;
            }

            const item = e.target.closest('.provider-sidebar-item');
            if (!item) return;

            currentProviderIndex = parseInt(item.dataset.index);
            renderProvidersSidebar();
            renderProviderDetail(currentProviderIndex);
        });

        sidebar.querySelector('#provider-detail').addEventListener('click', (e) => {
            if (e.target.classList.contains('toggle-password')) {
                const targetId = e.target.dataset.target;
                const input = sidebar.querySelector(`#${targetId}`);
                if (input.type === 'password') {
                    input.type = 'text';
                    e.target.textContent = '🙈';
                } else {
                    input.type = 'password';
                    e.target.textContent = '👁️';
                }
            } else if (e.target.classList.contains('save-provider-btn')) {
                const index = parseInt(e.target.dataset.index);
                const providers = ConfigManager.getProviders();

                providers[index] = {
                    name: sidebar.querySelector(`#provider-name-${index}`).value,
                    url: sidebar.querySelector(`#provider-url-${index}`).value,
                    key: sidebar.querySelector(`#provider-key-${index}`).value
                };

                ConfigManager.saveProviders(providers);
                renderProvidersSidebar();
                updateModelSelect();
                alert('保存成功');
            } else if (e.target.classList.contains('fetch-models-btn')) {
                const providerIndex = parseInt(e.target.dataset.index);
                fetchAvailableModels(providerIndex);
            } else if (e.target.classList.contains('refresh-models-btn')) {
                const providerIndex = parseInt(e.target.dataset.index);
                fetchAvailableModels(providerIndex);
            } else if (e.target.classList.contains('add-model-icon')) {
                const providerIndex = parseInt(e.target.dataset.provider);
                const modelName = e.target.dataset.modelName;
                const models = ConfigManager.getModels(providerIndex);

                if (!models.includes(modelName)) {
                    models.push(modelName);
                    ConfigManager.saveModels(providerIndex, models);
                    renderProviderDetail(providerIndex);
                    updateModelSelect();

                    // 恢复可用模型列表显示
                    const availableSection = sidebar.querySelector(`#available-models-${providerIndex}`);
                    if (availableSection) {
                        availableSection.style.display = 'block';
                        const searchInput = sidebar.querySelector(`#model-search-${providerIndex}`);
                        if (searchInput) {
                            filterAvailableModels(providerIndex, searchInput.value);
                        }
                    }
                } else {
                    alert('该模型已存在');
                }
            } else if (e.target.classList.contains('add-model-btn')) {
                const providerIndex = parseInt(e.target.dataset.index);
                const models = ConfigManager.getModels(providerIndex);
                models.push('');
                ConfigManager.saveModels(providerIndex, models);
                renderProviderDetail(providerIndex);
            } else if (e.target.classList.contains('save-model-btn')) {
                const providerIndex = parseInt(e.target.dataset.provider);
                const modelIndex = parseInt(e.target.dataset.model);
                const input = e.target.closest('.model-item').querySelector('input');
                const models = ConfigManager.getModels(providerIndex);
                models[modelIndex] = input.value.trim();
                ConfigManager.saveModels(providerIndex, models);
                updateModelSelect();
                alert('模型保存成功');
            } else if (e.target.classList.contains('delete-model-btn')) {
                const providerIndex = parseInt(e.target.dataset.provider);
                const modelIndex = parseInt(e.target.dataset.model);
                if (!confirm('确定删除此模型吗?')) return;

                const models = ConfigManager.getModels(providerIndex);
                models.splice(modelIndex, 1);
                ConfigManager.saveModels(providerIndex, models);
                renderProviderDetail(providerIndex);
                updateModelSelect();
            }
        });

        renderProvidersSidebar();

        // 模型选择下拉菜单
        let currentSelectedModel = null;
        const modelDisplayBtn = sidebar.querySelector('#model-display-btn');
        const modelDropdown = sidebar.querySelector('#model-dropdown');
        const modelNameSpan = sidebar.querySelector('#model-name');

        const renderModelDropdown = () => {
            const providers = ConfigManager.getProviders();
            modelDropdown.textContent = '';

            providers.forEach((provider, providerIndex) => {
                const models = ConfigManager.getModels(providerIndex);
                models.forEach(model => {
                    const item = document.createElement('div');
                    item.className = 'model-dropdown-item';
                    const modelValue = JSON.stringify({provider: providerIndex, model: model});
                    if (currentSelectedModel === modelValue) {
                        item.classList.add('selected');
                    }
                    item.textContent = `${provider.name} - ${model}`;
                    item.dataset.value = modelValue;
                    modelDropdown.appendChild(item);
                });
            });
        };

        modelDisplayBtn.addEventListener('click', (e) => {
            e.stopPropagation();
            const isOpen = modelDropdown.style.display === 'block';
            modelDropdown.style.display = isOpen ? 'none' : 'block';
            modelDisplayBtn.classList.toggle('open', !isOpen);
            if (!isOpen) renderModelDropdown();
        });

        modelDropdown.addEventListener('click', (e) => {
            const item = e.target.closest('.model-dropdown-item');
            if (!item) return;

            currentSelectedModel = item.dataset.value;
            const config = JSON.parse(currentSelectedModel);
            const providers = ConfigManager.getProviders();
            const provider = providers[config.provider];
            modelNameSpan.textContent = `${provider.name} - ${config.model}`;
            modelDropdown.style.display = 'none';
            modelDisplayBtn.classList.remove('open');
        });

        document.addEventListener('click', () => {
            modelDropdown.style.display = 'none';
            modelDisplayBtn.classList.remove('open');
        });

        // 历史对话管理
        let currentConversationId = null;
        let conversationMessages = [];

        const renderConversations = () => {
            const conversations = ConfigManager.getConversations();
            const list = document.querySelector('.conversations-list');
            if (!list) {
                const sidebar = document.querySelector('#conversations-sidebar');
                sidebar.innerHTML = `
                    <div class="conversations-toolbar">
                        <button class="batch-delete-conv-btn">批量删除</button>
                    </div>
                    <div class="conversations-list"></div>
                `;
                
                sidebar.querySelector('.batch-delete-conv-btn').addEventListener('click', () => {
                    const checkboxes = sidebar.querySelectorAll('.conv-checkbox:checked');
                    if (checkboxes.length === 0) {
                        alert('请选择要删除的对话');
                        return;
                    }
                    if (!confirm(`确定删除选中的 ${checkboxes.length} 个对话吗?`)) return;

                    const conversations = ConfigManager.getConversations();
                    const idsToDelete = Array.from(checkboxes).map(cb => cb.dataset.id);
                    const filtered = conversations.filter(c => !idsToDelete.includes(c.id));
                    ConfigManager.saveConversations(filtered);

                    if (idsToDelete.includes(currentConversationId)) {
                        createNewConversation();
                    } else {
                        renderConversations();
                    }
                });
                
                return renderConversations();
            }

            list.textContent = '';

            conversations.forEach((conv) => {
                const item = document.createElement('div');
                item.className = 'conversation-item';
                if (conv.id === currentConversationId) {
                    item.classList.add('active');
                }
                item.dataset.id = conv.id;
                
                safeInnerHTML(item, `
                    <input type="checkbox" class="conv-checkbox" data-id="${conv.id}">
                    <span class="conv-title">${conv.title}</span>
                    <input type="text" class="conv-rename-input" value="${conv.title}">
                    <div class="conv-actions">
                        <button class="conv-action-btn rename-conv-btn" title="重命名">✏️</button>
                        <button class="conv-action-btn delete-conv-btn" title="删除">🗑️</button>
                    </div>
                `);
                
                list.appendChild(item);
            });
        };

        const saveCurrentConversation = () => {
            if (!currentConversationId || conversationMessages.length === 0) return;

            const conversations = ConfigManager.getConversations();
            const index = conversations.findIndex(c => c.id === currentConversationId);
            
            if (index !== -1) {
                conversations[index].messages = conversationMessages;
                conversations[index].updatedAt = Date.now();
                ConfigManager.saveConversations(conversations);
            }
        };

        const loadConversation = (id) => {
            saveCurrentConversation();

            const conversations = ConfigManager.getConversations();
            const conv = conversations.find(c => c.id === id);
            
            if (!conv) return;

            currentConversationId = id;
            conversationMessages = conv.messages || [];

            const messagesContainer = document.querySelector('#messages');
            messagesContainer.textContent = '';

            conversationMessages.forEach((msg, index) => {
                const msgDiv = document.createElement('div');
                msgDiv.className = `message ${msg.role}`;
                msgDiv.dataset.index = index;
                
                if (msg.role === 'user') {
                    // 如果是总结类型,显示简洁文本
                    msgDiv.textContent = msg.isSummary ? msg.displayText : msg.content;
                } else {
                    safeInnerHTML(msgDiv, msg.html || msg.content, msg.content);
                }
                
                // 添加操作按钮
                const actions = document.createElement('div');
                actions.className = 'message-actions';
                if (msg.role === 'ai') {
                    safeInnerHTML(actions, `
                        <button class="message-action-btn copy-msg-btn" title="复制">📋</button>
                        <button class="message-action-btn delete-msg-btn" title="删除">🗑️</button>
                        <button class="message-action-btn regenerate-msg-btn" title="重新生成">🔄</button>
                    `);
                } else {
                    safeInnerHTML(actions, `
                        <button class="message-action-btn copy-msg-btn" title="复制">📋</button>
                        <button class="message-action-btn delete-msg-btn" title="删除">🗑️</button>
                    `);
                }
                msgDiv.appendChild(actions);
                messagesContainer.appendChild(msgDiv);
            });

            renderConversations();
        };

        const createNewConversation = () => {
            saveCurrentConversation();

            const conversations = ConfigManager.getConversations();
            const newConv = {
                id: Date.now().toString(),
                title: '新对话',
                messages: [],
                createdAt: Date.now(),
                updatedAt: Date.now()
            };

            conversations.unshift(newConv);
            ConfigManager.saveConversations(conversations);

            currentConversationId = newConv.id;
            conversationMessages = [];

            document.querySelector('#messages').textContent = '';
            renderConversations();
            
            // 应用系统配置的默认设置
            const systemConfig = ConfigManager.getSystemConfig();
            if (systemConfig.defaultModel) {
                currentSelectedModel = systemConfig.defaultModel;
                const config = JSON.parse(currentSelectedModel);
                const providers = ConfigManager.getProviders();
                const provider = providers[config.provider];
                if (provider) {
                    modelNameSpan.textContent = `${provider.name} - ${config.model}`;
                }
            }
            if (systemConfig.defaultPrompt !== null) {
                const prompts = ConfigManager.getPrompts();
                const prompt = prompts[systemConfig.defaultPrompt];
                if (prompt) {
                    currentSystemPrompt = prompt.content;
                    promptSelectorBtn.classList.add('selected');
                    promptSelectorBtn.title = `已选择: ${prompt.title}`;
                }
            }
        };

        document.querySelector('#conversations-sidebar').addEventListener('click', (e) => {
            if (e.target.classList.contains('conv-checkbox')) {
                e.stopPropagation();
                return;
            }

            if (e.target.classList.contains('delete-conv-btn')) {
                e.stopPropagation();
                const item = e.target.closest('.conversation-item');
                const id = item.dataset.id;
                
                if (!confirm('确定删除此对话吗?')) return;

                const conversations = ConfigManager.getConversations();
                const filtered = conversations.filter(c => c.id !== id);
                ConfigManager.saveConversations(filtered);

                if (id === currentConversationId) {
                    createNewConversation();
                } else {
                    renderConversations();
                }
                return;
            }

            if (e.target.classList.contains('rename-conv-btn')) {
                e.stopPropagation();
                const item = e.target.closest('.conversation-item');
                const input = item.querySelector('.conv-rename-input');
                
                item.classList.add('editing');
                input.focus();
                input.select();
                return;
            }

            const item = e.target.closest('.conversation-item');
            if (!item || item.classList.contains('editing')) return;
            loadConversation(item.dataset.id);
        });

        document.querySelector('#conversations-sidebar').addEventListener('keydown', (e) => {
            if (e.key === 'Enter' && e.target.classList.contains('conv-rename-input')) {
                const item = e.target.closest('.conversation-item');
                const id = item.dataset.id;
                const newTitle = e.target.value.trim();

                if (newTitle) {
                    const conversations = ConfigManager.getConversations();
                    const conv = conversations.find(c => c.id === id);
                    if (conv) {
                        conv.title = newTitle;
                        ConfigManager.saveConversations(conversations);
                    }
                }

                item.classList.remove('editing');
                renderConversations();
            } else if (e.key === 'Escape' && e.target.classList.contains('conv-rename-input')) {
                const item = e.target.closest('.conversation-item');
                item.classList.remove('editing');
            }
        });

        document.querySelector('#conversations-sidebar').addEventListener('blur', (e) => {
            if (e.target.classList.contains('conv-rename-input')) {
                const item = e.target.closest('.conversation-item');
                setTimeout(() => {
                    if (item.classList.contains('editing')) {
                        item.classList.remove('editing');
                    }
                }, 200);
            }
        }, true);

        document.querySelector('#new-chat-btn').addEventListener('click', createNewConversation);

        // 清除对话功能
        document.querySelector('#clear-chat-btn').addEventListener('click', () => {
            if (confirm('确定要清除当前对话记录吗?')) {
                conversationMessages = [];
                document.querySelector('#messages').textContent = '';
                saveCurrentConversation();
            }
        });

        // 总结网页功能
        document.querySelector('#summarize-page-btn').addEventListener('click', async () => {
            if (!currentSelectedModel) {
                alert('请先选择模型');
                return;
            }

            const input = sidebar.querySelector('#user-input');
            const messages = sidebar.querySelector('#messages');

            // 提取页面内容
            const pageTitle = document.title;
            const pageUrl = window.location.href;
            
            // 获取页面主要文本内容
            let pageContent = '';
            
            // 尝试获取主要内容区域
            const mainContent = document.querySelector('main, article, .content, .main, #content, #main');
            if (mainContent) {
                pageContent = mainContent.innerText;
            } else {
                pageContent = document.body.innerText;
            }
            
            // 限制内容长度,避免超出token限制
            const maxLength = 8000;
            if (pageContent.length > maxLength) {
                pageContent = pageContent.substring(0, maxLength) + '...(内容过长已截断)';
            }

            // 构建实际发送给AI的完整提示词
            const actualPrompt = `请详细总结以下网页的内容。要求:
1. 准确概括网页的主题和核心内容
2. 列出关键信息点和重要细节
3. 保持逻辑清晰,结构分明
4. 不要遗漏重要信息
5. 如果是文章,请总结主要观点;如果是产品页面,请总结产品特点;如果是新闻,请总结事件要点

网页标题:${pageTitle}
网页地址:${pageUrl}

网页内容:
${pageContent}

请开始总结:`;

            // 显示给用户的简洁文本
            const displayText = `总结当前页面:${pageTitle}`;

            // 如果是新对话的第一条消息,自动命名
            if (conversationMessages.length === 0) {
                const conversations = ConfigManager.getConversations();
                const index = conversations.findIndex(c => c.id === currentConversationId);
                if (index !== -1) {
                    conversations[index].title = displayText.slice(0, 20);
                    ConfigManager.saveConversations(conversations);
                    renderConversations();
                }
            }

            // 显示用户消息(简洁版本)
            const userMsg = document.createElement('div');
            userMsg.className = 'message user';
            userMsg.dataset.index = conversationMessages.length;
            userMsg.textContent = displayText;
            
            const userActions = document.createElement('div');
            userActions.className = 'message-actions';
            safeInnerHTML(userActions, `
                <button class="message-action-btn copy-msg-btn" title="复制">📋</button>
                <button class="message-action-btn delete-msg-btn" title="删除">🗑️</button>
            `);
            userMsg.appendChild(userActions);
            messages.appendChild(userMsg);
            
            // 保存到历史(保存完整提示词用于API调用,但标记为总结类型)
            conversationMessages.push({role: 'user', content: actualPrompt, displayText: displayText, isSummary: true});
            
            input.value = '';
            messages.scrollTop = messages.scrollHeight;

            const config = JSON.parse(currentSelectedModel);
            const providers = ConfigManager.getProviders();
            const provider = providers[config.provider];

            const aiMsg = document.createElement('div');
            aiMsg.className = 'message ai';
            aiMsg.textContent = '正在总结...';
            messages.appendChild(aiMsg);

            try {
                const finalUrl = normalizeApiUrl(provider.url);
                let fullContent = '';
                let buffer = '';
                let lastIndex = 0;

                let updateScheduled = false;
                let isStreamComplete = false;
                const updateUI = () => {
                    if (updateScheduled) return;
                    updateScheduled = true;
                    requestAnimationFrame(() => {
                        const thinkMatch = fullContent.match(/<think>([\s\S]*?)<\/think>/);
                        let thinkingContent = '';
                        let mainContent = fullContent;

                        if (thinkMatch) {
                            thinkingContent = thinkMatch[1].trim();
                            mainContent = fullContent.replace(/<think>[\s\S]*?<\/think>/, '').trim();
                        }

                        let html = '';
                        if (thinkingContent) {
                            const collapsed = isStreamComplete ? 'collapsed' : '';
                            html += `<div class="thinking-section">
                                <div class="thinking-header">
                                    <span class="thinking-toggle ${collapsed}">▼</span>
                                    <span>思考过程</span>
                                </div>
                                <div class="thinking-content ${collapsed}">${marked.parse(thinkingContent)}</div>
                            </div>`;
                        }
                        if (mainContent) {
                            html += marked.parse(mainContent);
                        }

                        safeInnerHTML(aiMsg, html, fullContent);
                        aiMsg.querySelectorAll('pre code').forEach((block) => {
                            hljs.highlightElement(block);
                        });

                        const thinkingHeader = aiMsg.querySelector('.thinking-header');
                        if (thinkingHeader && !thinkingHeader.dataset.listenerAdded) {
                            thinkingHeader.dataset.listenerAdded = 'true';
                            thinkingHeader.addEventListener('click', () => {
                                const toggle = thinkingHeader.querySelector('.thinking-toggle');
                                const content = thinkingHeader.nextElementSibling;
                                toggle.classList.toggle('collapsed');
                                content.classList.toggle('collapsed');
                            });
                        }

                        messages.scrollTop = messages.scrollHeight;
                        updateScheduled = false;
                    });
                };

                const processStreamLine = (line) => {
                    const trimmedLine = line.trim();
                    if (!trimmedLine.startsWith('data:')) return;

                    const data = trimmedLine.slice(5).trim();
                    if (data === '[DONE]') return;

                    try {
                        const parsed = JSON.parse(data);
                        let delta = '';
                        if (parsed.choices && parsed.choices.length > 0) {
                            const choice = parsed.choices[0];
                            if (choice.delta && choice.delta.content) {
                                delta = choice.delta.content;
                            } else if (choice.message && choice.message.content) {
                                delta = choice.message.content;
                            } else if (choice.text) {
                                delta = choice.text;
                            }
                        } else if (parsed.content) {
                            delta = parsed.content;
                        }

                        if (delta) {
                            fullContent += delta;
                            updateUI();
                        }
                    } catch (e) {
                        // 忽略解析错误
                    }
                };

                const buildMessages = () => {
                    const messages = [];
                    if (currentSystemPrompt) {
                        messages.push({role: 'system', content: currentSystemPrompt});
                    }
                    
                    const memoryRounds = modelParams.memory_rounds;
                    if (memoryRounds > 0 && conversationMessages.length > 0) {
                        const maxMessages = memoryRounds * 2;
                        const startIndex = Math.max(0, conversationMessages.length - maxMessages);
                        const historyMessages = conversationMessages.slice(startIndex);
                        
                        historyMessages.forEach(msg => {
                            messages.push({
                                role: msg.role === 'ai' ? 'assistant' : msg.role,
                                content: msg.content
                            });
                        });
                    }
                    
                    messages.push({role: 'user', content: actualPrompt});
                    return messages;
                };

                const requestData = {
                    model: config.model,
                    messages: buildMessages(),
                    temperature: modelParams.temperature,
                    max_tokens: modelParams.max_tokens,
                    stream: true
                };

                try {
                    aiMsg.textContent = '';
                    const response = await fetch(finalUrl, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'Authorization': `Bearer ${provider.key}`
                        },
                        body: JSON.stringify(requestData)
                    });

                    if (!response.ok) {
                        throw new Error(`HTTP error! status: ${response.status}`);
                    }

                    const reader = response.body.getReader();
                    const decoder = new TextDecoder();

                    while (true) {
                        const { done, value } = await reader.read();
                        if (done) break;

                        const chunk = decoder.decode(value, { stream: true });
                        buffer += chunk;
                        const lines = buffer.split('\n');
                        buffer = lines.pop();
                        lines.forEach(processStreamLine);
                    }

                    if (buffer) processStreamLine(buffer);
                    isStreamComplete = true;
                    
                    // 等待最后一次 UI 更新完成
                    requestAnimationFrame(() => {
                        // 流式完成后添加操作按钮
                        const aiActions = document.createElement('div');
                        aiActions.className = 'message-actions';
                        safeInnerHTML(aiActions, `
                            <button class="message-action-btn copy-msg-btn" title="复制">📋</button>
                            <button class="message-action-btn delete-msg-btn" title="删除">🗑️</button>
                            <button class="message-action-btn regenerate-msg-btn" title="重新生成">🔄</button>
                        `);
                        aiMsg.appendChild(aiActions);
                        aiMsg.dataset.index = conversationMessages.length;

                        conversationMessages.push({role: 'ai', content: fullContent, html: aiMsg.innerHTML});
                        saveCurrentConversation();
                    });

                } catch (fetchError) {
                    console.warn('Fetch failed, falling back to GM_xmlhttpRequest:', fetchError);
                    // GM_xmlhttpRequest 回退逻辑保持不变...
                    aiMsg.textContent = '请求失败: ' + fetchError.message;
                }
            } catch (e) {
                aiMsg.textContent = '发送失败: ' + e.message;
            }
        });

        // 初始化对话 - 检查是否已有对话,避免每次刷新都创建新对话
        const conversations = ConfigManager.getConversations();
        if (conversations.length > 0) {
            // 加载最近的对话
            loadConversation(conversations[0].id);
        } else {
            // 只有在没有任何对话时才创建新对话
            createNewConversation();
        }

        // 提示词选择下拉菜单
        let currentSystemPrompt = '';
        const promptSelectorBtn = sidebar.querySelector('#prompt-selector-btn');
        const promptDropdown = sidebar.querySelector('#prompt-dropdown');

        const renderPromptDropdown = () => {
            const prompts = ConfigManager.getPrompts();
            promptDropdown.textContent = '';

            if (prompts.length === 0) {
                safeInnerHTML(promptDropdown, '<div class="prompt-dropdown-item" style="text-align:center;color:#999;">暂无提示词</div>');
                return;
            }

            prompts.forEach((prompt, index) => {
                const item = document.createElement('div');
                item.className = 'prompt-dropdown-item';
                safeInnerHTML(item, `
                    <div class="prompt-title">${prompt.title || '未命名'}</div>
                    <div class="prompt-preview">${prompt.content || ''}</div>
                `);
                item.dataset.index = index;
                promptDropdown.appendChild(item);
            });
        };

        promptSelectorBtn.addEventListener('click', (e) => {
            e.stopPropagation();
            const isOpen = promptDropdown.style.display === 'block';
            promptDropdown.style.display = isOpen ? 'none' : 'block';
            sidebar.querySelector('#params-panel').style.display = 'none';
            sidebar.querySelector('#params-selector-btn').classList.remove('selected');
            if (!isOpen) renderPromptDropdown();
        });

        // 模型参数设置
        let modelParams = {temperature: 0.7, max_tokens: 2048, memory_rounds: 15};
        const paramsSelectorBtn = sidebar.querySelector('#params-selector-btn');
        const paramsPanel = sidebar.querySelector('#params-panel');
        const tempInput = sidebar.querySelector('#param-temperature');
        const maxTokensInput = sidebar.querySelector('#param-max-tokens');
        const memoryInput = sidebar.querySelector('#param-memory-rounds');

        paramsSelectorBtn.addEventListener('click', (e) => {
            e.stopPropagation();
            const isOpen = paramsPanel.style.display === 'block';
            paramsPanel.style.display = isOpen ? 'none' : 'block';
            promptDropdown.style.display = 'none';
            paramsSelectorBtn.classList.toggle('selected', !isOpen);
        });

        tempInput.addEventListener('input', (e) => {
            modelParams.temperature = parseFloat(e.target.value) || 0.7;
        });

        maxTokensInput.addEventListener('input', (e) => {
            modelParams.max_tokens = parseInt(e.target.value) || 2048;
        });

        memoryInput.addEventListener('input', (e) => {
            modelParams.memory_rounds = parseInt(e.target.value) || 15;
        });

        promptDropdown.addEventListener('click', (e) => {
            const item = e.target.closest('.prompt-dropdown-item');
            if (!item || !item.dataset.index) return;

            const prompts = ConfigManager.getPrompts();
            const prompt = prompts[parseInt(item.dataset.index)];
            currentSystemPrompt = prompt.content;
            promptDropdown.style.display = 'none';
            promptSelectorBtn.classList.add('selected');
            promptSelectorBtn.title = `已选择: ${prompt.title}`;
        });

        // 初始化加载模型和提示词
        renderModelDropdown();
        renderPromptDropdown();

        document.addEventListener('click', (e) => {
            if (!e.target.closest('.input-area')) {
                promptDropdown.style.display = 'none';
                paramsPanel.style.display = 'none';
                paramsSelectorBtn.classList.remove('selected');
            }
        });

        // 对话功能
        const sendMessage = async () => {
            const input = sidebar.querySelector('#user-input');
            const messages = sidebar.querySelector('#messages');
            const select = sidebar.querySelector('#model-select');
            const text = input.value.trim();

            if (!text) return;
            if (!currentSelectedModel) {
                alert('请先选择模型');
                return;
            }

            // 如果是新对话的第一条消息,自动命名
            if (conversationMessages.length === 0) {
                const conversations = ConfigManager.getConversations();
                const index = conversations.findIndex(c => c.id === currentConversationId);
                if (index !== -1) {
                    conversations[index].title = text.slice(0, 20);
                    ConfigManager.saveConversations(conversations);
                    renderConversations();
                }
            }

            const userMsg = document.createElement('div');
            userMsg.className = 'message user';
            userMsg.dataset.index = conversationMessages.length;
            userMsg.textContent = text;
            
            const userActions = document.createElement('div');
            userActions.className = 'message-actions';
            safeInnerHTML(userActions, `
                <button class="message-action-btn copy-msg-btn" title="复制">📋</button>
                <button class="message-action-btn delete-msg-btn" title="删除">🗑️</button>
            `);
            userMsg.appendChild(userActions);
            messages.appendChild(userMsg);
            
            conversationMessages.push({role: 'user', content: text});
            
            input.value = '';
            messages.scrollTop = messages.scrollHeight;

            const config = JSON.parse(currentSelectedModel);
            const providers = ConfigManager.getProviders();
            const provider = providers[config.provider];

            const aiMsg = document.createElement('div');
            aiMsg.className = 'message ai';
            aiMsg.textContent = '思考中...';
            messages.appendChild(aiMsg);

            try {
                const finalUrl = normalizeApiUrl(provider.url);
                let fullContent = '';
                let buffer = '';
                let lastIndex = 0;

                // UI 更新节流
                let updateScheduled = false;
                let isStreamComplete = false;
                const updateUI = () => {
                    if (updateScheduled) return;
                    updateScheduled = true;
                    requestAnimationFrame(() => {
                        // 分离思考过程和正文
                        const thinkMatch = fullContent.match(/<think>([\s\S]*?)<\/think>/);
                        let thinkingContent = '';
                        let mainContent = fullContent;

                        if (thinkMatch) {
                            thinkingContent = thinkMatch[1].trim();
                            mainContent = fullContent.replace(/<think>[\s\S]*?<\/think>/, '').trim();
                        }

                        let html = '';
                        if (thinkingContent) {
                            const collapsed = isStreamComplete ? 'collapsed' : '';
                            html += `<div class="thinking-section">
                                <div class="thinking-header">
                                    <span class="thinking-toggle ${collapsed}">▼</span>
                                    <span>思考过程</span>
                                </div>
                                <div class="thinking-content ${collapsed}">${marked.parse(thinkingContent)}</div>
                            </div>`;
                        }
                        if (mainContent) {
                            html += marked.parse(mainContent);
                        }

                        safeInnerHTML(aiMsg, html, fullContent);
                        aiMsg.querySelectorAll('pre code').forEach((block) => {
                            hljs.highlightElement(block);
                        });

                        // 添加折叠功能
                        const thinkingHeader = aiMsg.querySelector('.thinking-header');
                        if (thinkingHeader && !thinkingHeader.dataset.listenerAdded) {
                            thinkingHeader.dataset.listenerAdded = 'true';
                            thinkingHeader.addEventListener('click', () => {
                                const toggle = thinkingHeader.querySelector('.thinking-toggle');
                                const content = thinkingHeader.nextElementSibling;
                                toggle.classList.toggle('collapsed');
                                content.classList.toggle('collapsed');
                            });
                        }

                        messages.scrollTop = messages.scrollHeight;
                        updateScheduled = false;
                    });
                };

                const processStreamLine = (line) => {
                    const trimmedLine = line.trim();
                    if (!trimmedLine.startsWith('data:')) return;

                    const data = trimmedLine.slice(5).trim();
                    if (data === '[DONE]') return;

                    try {
                        const parsed = JSON.parse(data);
                        let delta = '';
                        if (parsed.choices && parsed.choices.length > 0) {
                            const choice = parsed.choices[0];
                            if (choice.delta && choice.delta.content) {
                                delta = choice.delta.content;
                            } else if (choice.message && choice.message.content) {
                                delta = choice.message.content;
                            } else if (choice.text) {
                                delta = choice.text;
                            }
                        } else if (parsed.content) {
                            delta = parsed.content;
                        }

                        if (delta) {
                            fullContent += delta;
                            updateUI();
                        }
                    } catch (e) {
                        // 忽略解析错误
                    }
                };

                // 构建消息历史
                const buildMessages = () => {
                    const messages = [];
                    if (currentSystemPrompt) {
                        messages.push({role: 'system', content: currentSystemPrompt});
                    }
                    
                    // 获取历史消息
                    const memoryRounds = modelParams.memory_rounds;
                    if (memoryRounds > 0 && conversationMessages.length > 0) {
                        // 计算需要包含的消息数量(每轮包含用户和AI两条消息)
                        const maxMessages = memoryRounds * 2;
                        const startIndex = Math.max(0, conversationMessages.length - maxMessages);
                        const historyMessages = conversationMessages.slice(startIndex);
                        
                        historyMessages.forEach(msg => {
                            messages.push({
                                role: msg.role === 'ai' ? 'assistant' : msg.role,
                                content: msg.content
                            });
                        });
                    }
                    
                    // 添加当前用户消息
                    messages.push({role: 'user', content: text});
                    return messages;
                };

                const requestData = {
                    model: config.model,
                    messages: buildMessages(),
                    temperature: modelParams.temperature,
                    max_tokens: modelParams.max_tokens,
                    stream: true
                };

                // 优先尝试使用 fetch (支持流式)
                try {
                    aiMsg.textContent = '';
                    const response = await fetch(finalUrl, {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json',
                            'Authorization': `Bearer ${provider.key}`
                        },
                        body: JSON.stringify(requestData)
                    });

                    if (!response.ok) {
                        throw new Error(`HTTP error! status: ${response.status}`);
                    }

                    const reader = response.body.getReader();
                    const decoder = new TextDecoder();

                    while (true) {
                        const { done, value } = await reader.read();
                        if (done) break;

                        const chunk = decoder.decode(value, { stream: true });
                        buffer += chunk;
                        const lines = buffer.split('\n');
                        buffer = lines.pop();
                        lines.forEach(processStreamLine);
                    }

                    // 处理剩余 buffer
                    if (buffer) processStreamLine(buffer);
                    isStreamComplete = true;
                    
                    // 等待最后一次 UI 更新完成后再添加按钮
                    requestAnimationFrame(() => {
                        updateUI();
                        requestAnimationFrame(() => {
                            // 流式完成后添加操作按钮
                            const aiActions = document.createElement('div');
                            aiActions.className = 'message-actions';
                            safeInnerHTML(aiActions, `
                                <button class="message-action-btn copy-msg-btn" title="复制">📋</button>
                                <button class="message-action-btn delete-msg-btn" title="删除">🗑️</button>
                                <button class="message-action-btn regenerate-msg-btn" title="重新生成">🔄</button>
                            `);
                            aiMsg.appendChild(aiActions);
                            aiMsg.dataset.index = conversationMessages.length;

                            // 保存AI回复
                            conversationMessages.push({role: 'ai', content: fullContent, html: aiMsg.innerHTML});
                            saveCurrentConversation();
                        });
                    });

                } catch (fetchError) {
                    console.warn('Fetch failed, falling back to GM_xmlhttpRequest:', fetchError);

                    // 如果 fetch 失败 (可能是 CORS),回退到 GM_xmlhttpRequest
                    // 注意:GM_xmlhttpRequest 在某些环境下可能不支持流式,会退化为一次性输出
                    GM_xmlhttpRequest({
                        method: 'POST',
                        url: finalUrl,
                        headers: {
                            'Content-Type': 'application/json',
                            'Authorization': `Bearer ${provider.key}`
                        },
                        data: JSON.stringify(requestData),
                        onloadstart: () => {
                            if (!fullContent) aiMsg.textContent = '正在重试...';
                        },
                        onprogress: (response) => {
                            const responseText = response.responseText;
                            if (!responseText) return;

                            const newText = responseText.slice(lastIndex);
                            if (newText.length === 0) return;
                            lastIndex = responseText.length;
                            buffer += newText;

                            const lines = buffer.split('\n');
                            buffer = lines.pop();

                            lines.forEach(processStreamLine);
                        },
                        onload: (response) => {
                            if (buffer) processStreamLine(buffer);
                            isStreamComplete = true;
                            updateUI();

                            // 保存AI回复
                            if (fullContent) {
                                // 添加AI消息操作按钮
                                const aiActions = document.createElement('div');
                                aiActions.className = 'message-actions';
                                safeInnerHTML(aiActions, `
                                    <button class="message-action-btn copy-msg-btn" title="复制">📋</button>
                                    <button class="message-action-btn delete-msg-btn" title="删除">🗑️</button>
                                    <button class="message-action-btn regenerate-msg-btn" title="重新生成">🔄</button>
                                `);
                                aiMsg.appendChild(aiActions);
                                aiMsg.dataset.index = conversationMessages.length;

                                conversationMessages.push({role: 'ai', content: fullContent, html: aiMsg.innerHTML});
                                saveCurrentConversation();
                            }

                            if (!fullContent) {
                                // 最后的兜底解析
                                try {
                                    const data = JSON.parse(response.responseText);
                                    if (data.choices && data.choices[0]?.message?.content) {
                                        fullContent = data.choices[0].message.content;
                                        updateUI();
                                    } else if (data.error) {
                                        aiMsg.textContent = 'API错误: ' + (data.error.message || JSON.stringify(data.error));
                                    }
                                } catch (e) {
                                    aiMsg.textContent = '请求失败: ' + (fetchError.message || '未知错误');
                                }
                            }
                        },
                        onerror: (err) => {
                            aiMsg.textContent = '请求失败: ' + (err.statusText || '网络错误');
                        }
                    });
                }
            } catch (e) {
                aiMsg.textContent = '发送失败: ' + e.message;
            }
        };

        // 消息操作事件处理
        sidebar.querySelector('#messages').addEventListener('click', async (e) => {
            const btn = e.target.closest('.message-action-btn');
            if (!btn) return;

            const msgDiv = btn.closest('.message');
            const msgIndex = parseInt(msgDiv.dataset.index);

            if (btn.classList.contains('copy-msg-btn')) {
                // 复制消息
                const msg = conversationMessages[msgIndex];
                try {
                    await navigator.clipboard.writeText(msg.content);
                    btn.textContent = '✓';
                    setTimeout(() => btn.textContent = '📋', 1000);
                } catch (err) {
                    alert('复制失败');
                }
            } else if (btn.classList.contains('delete-msg-btn')) {
                // 删除消息
                if (!confirm('确定删除此消息吗?')) return;
                
                conversationMessages.splice(msgIndex, 1);
                msgDiv.remove();
                
                // 更新后续消息的索引
                const allMsgs = sidebar.querySelectorAll('#messages .message');
                allMsgs.forEach((m, i) => {
                    m.dataset.index = i;
                });
                
                saveCurrentConversation();
            } else if (btn.classList.contains('regenerate-msg-btn')) {
                // 重新生成
                if (!confirm('确定重新生成此回复吗?')) return;
                
                // 删除当前AI消息
                conversationMessages.splice(msgIndex, 1);
                msgDiv.remove();
                
                // 更新后续消息的索引
                const allMsgs = sidebar.querySelectorAll('#messages .message');
                allMsgs.forEach((m, i) => {
                    m.dataset.index = i;
                });
                
                // 获取上一条用户消息并重新发送
                const userMsg = conversationMessages[msgIndex - 1];
                if (userMsg && userMsg.role === 'user') {
                    const input = sidebar.querySelector('#user-input');
                    input.value = userMsg.content;
                    
                    // 删除用户消息,因为sendMessage会重新添加
                    conversationMessages.splice(msgIndex - 1, 1);
                    const userMsgDiv = sidebar.querySelector(`#messages .message[data-index="${msgIndex - 1}"]`);
                    if (userMsgDiv) userMsgDiv.remove();
                    
                    // 更新索引
                    const updatedMsgs = sidebar.querySelectorAll('#messages .message');
                    updatedMsgs.forEach((m, i) => {
                        m.dataset.index = i;
                    });
                    
                    await sendMessage();
                }
            }
        });

        sidebar.querySelector('#send-btn').addEventListener('click', sendMessage);
        sidebar.querySelector('#user-input').addEventListener('keydown', (e) => {
            if (e.key === 'Enter' && !e.shiftKey) {
                e.preventDefault();
                sendMessage();
            }
        });

        // 提示词库功能
        const renderPrompts = () => {
            const prompts = ConfigManager.getPrompts();
            const list = sidebar.querySelector('#prompts-list');
            list.textContent = '';

            prompts.forEach((prompt, index) => {
                const item = document.createElement('div');
                item.className = 'prompt-item';
                item.dataset.index = index;
                safeInnerHTML(item, `
                    <input type="checkbox" class="prompt-checkbox" data-index="${index}">
                    <div class="prompt-header">
                        <div class="prompt-title">${prompt.title || '未命名'}</div>
                        <div class="prompt-actions">
                            <button class="view-btn" data-index="${index}">查看</button>
                            <button class="edit-btn" data-index="${index}">编辑</button>
                            <button class="delete-btn" data-index="${index}">删除</button>
                        </div>
                    </div>
                    <div class="prompt-content" style="display:none;">${prompt.content || ''}</div>
                `);
                list.appendChild(item);
            });
        };

        sidebar.querySelector('#add-prompt').addEventListener('click', () => {
            const prompts = ConfigManager.getPrompts();
            prompts.push({title: '', content: ''});
            ConfigManager.savePrompts(prompts);
            renderPrompts();
            const items = sidebar.querySelectorAll('.prompt-item');
            const lastItem = items[items.length - 1];
            if (lastItem) {
                lastItem.querySelector('.edit-btn').click();
            }
        });

        sidebar.querySelector('#batch-delete-prompt').addEventListener('click', () => {
            const checkboxes = sidebar.querySelectorAll('.prompt-checkbox:checked');
            if (checkboxes.length === 0) {
                alert('请选择要删除的提示词');
                return;
            }
            if (!confirm(`确定删除选中的 ${checkboxes.length} 个提示词吗?`)) return;

            const prompts = ConfigManager.getPrompts();
            const indices = Array.from(checkboxes).map(cb => parseInt(cb.dataset.index)).sort((a, b) => b - a);
            indices.forEach(index => prompts.splice(index, 1));
            ConfigManager.savePrompts(prompts);
            renderPrompts();
        });

        sidebar.querySelector('#prompts-list').addEventListener('click', (e) => {
            const index = parseInt(e.target.dataset.index);
            const item = sidebar.querySelector(`.prompt-item[data-index="${index}"]`);

            if (e.target.classList.contains('view-btn')) {
                const content = item.querySelector('.prompt-content');
                content.style.display = content.style.display === 'none' ? 'block' : 'none';
            } else if (e.target.classList.contains('edit-btn')) {
                const prompts = ConfigManager.getPrompts();
                const prompt = prompts[index];
                item.classList.add('editing');
                safeInnerHTML(item, `
                    <div class="prompt-form">
                        <input type="text" placeholder="标题" value="${prompt.title || ''}" class="prompt-title-input">
                        <textarea placeholder="内容" class="prompt-content-input">${prompt.content || ''}</textarea>
                        <div class="form-actions">
                            <button class="save-prompt-btn" data-index="${index}">保存</button>
                            <button class="cancel-btn" data-index="${index}">取消</button>
                        </div>
                    </div>
                `);
            } else if (e.target.classList.contains('delete-btn')) {
                if (!confirm('确定删除此提示词吗?')) return;
                const prompts = ConfigManager.getPrompts();
                prompts.splice(index, 1);
                ConfigManager.savePrompts(prompts);
                renderPrompts();
            } else if (e.target.classList.contains('save-prompt-btn')) {
                const prompts = ConfigManager.getPrompts();
                const titleInput = item.querySelector('.prompt-title-input');
                const contentInput = item.querySelector('.prompt-content-input');
                prompts[index] = {
                    title: titleInput.value.trim() || '未命名',
                    content: contentInput.value.trim()
                };
                ConfigManager.savePrompts(prompts);
                renderPrompts();
            } else if (e.target.classList.contains('cancel-btn')) {
                renderPrompts();
            }
        });

        renderPrompts();
        
        // 系统配置功能
        const renderSystemConfig = () => {
            const systemConfig = ConfigManager.getSystemConfig();
            const modelSelect = sidebar.querySelector('#default-model-select');
            const promptSelect = sidebar.querySelector('#default-prompt-select');
            
            // 填充模型选项
            modelSelect.innerHTML = '<option value="">未设置</option>';
            const providers = ConfigManager.getProviders();
            providers.forEach((provider, providerIndex) => {
                const models = ConfigManager.getModels(providerIndex);
                models.forEach(model => {
                    const option = document.createElement('option');
                    const modelValue = JSON.stringify({provider: providerIndex, model: model});
                    option.value = modelValue;
                    option.textContent = `${provider.name} - ${model}`;
                    if (systemConfig.defaultModel === modelValue) {
                        option.selected = true;
                    }
                    modelSelect.appendChild(option);
                });
            });
            
            // 填充提示词选项
            promptSelect.innerHTML = '<option value="">未设置</option>';
            const prompts = ConfigManager.getPrompts();
            prompts.forEach((prompt, index) => {
                const option = document.createElement('option');
                option.value = index;
                option.textContent = prompt.title || '未命名';
                if (systemConfig.defaultPrompt === index) {
                    option.selected = true;
                }
                promptSelect.appendChild(option);
            });
        };
        
        sidebar.querySelector('#save-system-config').addEventListener('click', () => {
            const modelSelect = sidebar.querySelector('#default-model-select');
            const promptSelect = sidebar.querySelector('#default-prompt-select');
            
            const config = {
                defaultModel: modelSelect.value || null,
                defaultPrompt: promptSelect.value ? parseInt(promptSelect.value) : null
            };
            
            ConfigManager.saveSystemConfig(config);
            alert('系统配置已保存');
        });
        
        // 监听标签页切换,当切换到系统配置时刷新选项
        sidebar.querySelectorAll('.tab').forEach(tab => {
            tab.addEventListener('click', () => {
                if (tab.dataset.tab === 'system') {
                    renderSystemConfig();
                }
            });
        });
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();