📜
settings.js
Back
📝 Javascript ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
// settings.js - Settings Module for AppOverlay System (with Debug Mode + quick prompt buttons) // Drop-in replacement. window.App = window.App || {}; window.AppItems = window.AppItems || []; (() => { const MODEL_PRICING = { 'deepseek-chat': { input: 0.27, output: 1.10, inputCache: 0.07 }, 'deepseek-reasoner': { input: 0.55, output: 2.19, inputCache: 0.14 }, 'gpt-4o': { input: 2.50, output: 10.00 }, 'gpt-4o-mini': { input: 0.15, output: 0.60 }, 'gpt-5': { input: 1.25, output: 10.00 }, 'gpt-5-mini': { input: 0.25, output: 2.00 }, 'gpt-5-nano': { input: 0.05, output: 0.40 }, 'gpt-5-thinking': { input: 1.25, output: 10.00 }, 'gpt-5-pro': { input: 2.50, output: 15.00 }, 'grok-3': { input: 3.00, output: 15.00 }, 'grok-3-mini': { input: 0.30, output: 0.50 }, 'grok-code-fast-1': { input: 0.20, output: 1.50 }, 'grok-4-0709': { input: 3.00, output: 15.00 } }; const RECOMMENDED = { chunkedPrompt: "you are a coding assistant. Output only raw code. Do not explain, do not comment, do not use backticks. If the code is too long for one reply, stop exactly where you must and wait. When I say 'continue,' you will resume exactly where you left off, without repeating or skipping. At the very end of the entire document, output a single line containing exactly (END) and nothing else. You must always finish with (END). Never stop before (END) unless you are waiting for me to say 'continue'.", snippetsPrompt: "You are a coding assistant. Output the entire response inside a single triple-backtick code block. Do not explain anything outside the code block. Do not break across multiple responses. Complete the entire document inside the code block.", fullCodePrompt: "You are a coding assistant. Output only raw code with no explanations, no comments, and no backticks. Return the entire document in a single response if possible. Finish with a single line containing exactly (END).", continuePrompt: `Continue the exact same document from the very next character. Do NOT repeat any characters from the tail below. Output ONLY raw code (no backticks, no markdown, no explanations, no comments). When the entire document is done, output exactly (END) on its own line. <TAIL> {{TAIL}} </TAIL>` }; function generateSettingsHTML() { const s = App.state?.settings || { model: 'deepseek-chat', maxTokens: 800, temperature: 0.7, forceTemperature: false, includeArtifacts: false, jsonFormat: false, system: 'You are a helpful, accurate assistant. Be concise and clear. Use markdown when it helps readability.', codeStyle: 'default', fullCodePrompt: RECOMMENDED.fullCodePrompt, snippetsPrompt: RECOMMENDED.snippetsPrompt, chunkedPrompt: RECOMMENDED.chunkedPrompt, continuePrompt: RECOMMENDED.continuePrompt, debugMode: false }; // Ensure defaults exist if (!s.fullCodePrompt) s.fullCodePrompt = RECOMMENDED.fullCodePrompt; if (!s.snippetsPrompt) s.snippetsPrompt = RECOMMENDED.snippetsPrompt; if (!s.chunkedPrompt) s.chunkedPrompt = RECOMMENDED.chunkedPrompt; if (!s.continuePrompt) s.continuePrompt = RECOMMENDED.continuePrompt; if (typeof s.debugMode !== 'boolean') s.debugMode = false; return ` <div style="padding: 1.5rem; max-width: 800px; margin: 0 auto; background: #0f172a; color: #f1f5f9; overflow-y: auto; max-height: 70vh;"> <div style="margin-bottom: 1.5rem;"> <label style="display: block; font-size: 0.875rem; font-weight: 600; margin-bottom: 0.5rem; color: #e2e8f0;">Model</label> <select id="settingsModel" style="width: 100%; padding: 0.625rem; border-radius: 0.5rem; border: 1px solid #334155; background: #1e293b; color: #f1f5f9; font-size: 0.875rem;"> <optgroup label="OpenAI" style="background: #1e293b;"> <option value="gpt-5" ${s.model === 'gpt-5' ? 'selected' : ''}>gpt-5</option> <option value="gpt-5-mini" ${s.model === 'gpt-5-mini' ? 'selected' : ''}>gpt-5-mini</option> <option value="gpt-5-nano" ${s.model === 'gpt-5-nano' ? 'selected' : ''}>gpt-5-nano</option> <option value="gpt-5-thinking" ${s.model === 'gpt-5-thinking' ? 'selected' : ''}>gpt-5-thinking</option> <option value="gpt-5-pro" ${s.model === 'gpt-5-pro' ? 'selected' : ''}>gpt-5-pro</option> <option value="gpt-4o" ${s.model === 'gpt-4o' ? 'selected' : ''}>gpt-4o</option> <option value="gpt-4o-mini" ${s.model === 'gpt-4o-mini' ? 'selected' : ''}>gpt-4o-mini</option> </optgroup> <optgroup label="DeepSeek" style="background: #1e293b;"> <option value="deepseek-chat" ${s.model === 'deepseek-chat' ? 'selected' : ''}>deepseek-chat</option> <option value="deepseek-reasoner" ${s.model === 'deepseek-reasoner' ? 'selected' : ''}>deepseek-reasoner</option> </optgroup> <optgroup label="xAI (Grok)" style="background: #1e293b;"> <option value="grok-3" ${s.model === 'grok-3' ? 'selected' : ''}>grok-3</option> <option value="grok-3-mini" ${s.model === 'grok-3-mini' ? 'selected' : ''}>grok-3-mini</option> <option value="grok-code-fast-1" ${s.model === 'grok-code-fast-1' ? 'selected' : ''}>grok-code-fast-1</option> <option value="grok-4-0709" ${s.model === 'grok-4-0709' ? 'selected' : ''}>grok-4-0709</option> </optgroup> </select> </div> <div style="margin-bottom: 1.5rem;"> <label style="display: block; font-size: 0.875rem; font-weight: 600; margin-bottom: 0.5rem; color: #e2e8f0;"> Max Tokens: <span id="maxTokensDisplay" style="font-family: monospace; color: #a78bfa;">${s.maxTokens}</span> </label> <input id="settingsMaxTokens" type="range" min="64" max="4096" step="32" value="${s.maxTokens}" style="width: 100%; height: 8px; border-radius: 4px; background: #334155; outline: none; -webkit-appearance: none; appearance: none;"> </div> <div style="margin-bottom: 1.5rem;"> <label style="display: block; font-size: 0.875rem; font-weight: 600; margin-bottom: 0.5rem; color: #e2e8f0;"> Temperature: <span id="temperatureDisplay" style="font-family: monospace; color: #a78bfa;">${s.temperature}</span> </label> <input id="settingsTemperature" type="range" min="0" max="2" step="0.1" value="${s.temperature}" style="width: 100%; height: 8px; border-radius: 4px; background: #334155; outline: none; -webkit-appearance: none; appearance: none;"> <label style="display: flex; align-items: center; gap: 0.5rem; margin-top: 0.5rem; font-size: 0.75rem; color: #cbd5e1;"> <input id="settingsForceTemp" type="checkbox" ${s.forceTemperature ? 'checked' : ''} style="width: 16px; height: 16px;"> Force temperature (for GPT-5) </label> </div> <div style="margin-bottom: 1.5rem;"> <label style="display: block; font-size: 0.875rem; font-weight: 600; margin-bottom: 0.5rem; color: #e2e8f0;">System Prompt</label> <textarea id="settingsSystem" rows="4" placeholder="You are a helpful, accurate assistant..." style="width: 100%; padding: 0.75rem; border-radius: 0.5rem; border: 1px solid #334155; background: #1e293b; color: #f1f5f9; font-size: 0.875rem; font-family: inherit; resize: vertical;">${s.system || ''}</textarea> </div> <div style="margin-bottom: 1.5rem;"> <label style="display: block; font-size: 0.875rem; font-weight: 600; margin-bottom: 0.75rem; color: #e2e8f0;">Code Response Style</label> <!-- Quick action buttons --> <div style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.75rem;"> <button id="btnBackToDefault" title="Switch to Default style" style="padding: 0.5rem 0.75rem; border-radius: 0.5rem; border: 1px solid #334155; background:#0b1220; color:#e5e7eb; font-size:0.8125rem; cursor:pointer;"> ⟲ Back to Default </button> <button id="btnFullCodeLikeChunked" title="Set Full Code style and recommended prompt" style="padding: 0.5rem 0.75rem; border-radius: 0.5rem; border: 1px solid #334155; background:#0b1220; color:#e5e7eb; font-size:0.8125rem; cursor:pointer;"> ⤓ Use Full Code (like chunked) </button> <button id="btnUseChunkedPrompt" title="Set Chunked style with your recommended chunked prompt" style="padding: 0.5rem 0.75rem; border-radius: 0.5rem; border: 1px solid #334155; background:#0b1220; color:#e5e7eb; font-size:0.8125rem; cursor:pointer;"> ⤓ Use Chunked Prompt </button> <button id="btnUseSnippetsPrompt" title="Set Snippets style with your recommended snippets prompt" style="padding: 0.5rem 0.75rem; border-radius: 0.5rem; border: 1px solid #334155; background:#0b1220; color:#e5e7eb; font-size:0.8125rem; cursor:pointer;"> ⤓ Use Snippets Prompt </button> <button id="btnUseContinuePrompt" title="Apply the recommended Continue Prompt (uses {{TAIL}} placeholder)" style="padding: 0.5rem 0.75rem; border-radius: 0.5rem; border: 1px solid #334155; background:#0b1220; color:#e5e7eb; font-size:0.8125rem; cursor:pointer;"> ⤓ Use Continue Prompt (recommended) </button> </div> <!-- Style tabs --> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 0.5rem; margin-bottom: 0.75rem;"> <button id="tabDefault" style="padding: 0.625rem; border-radius: 0.5rem; border: 1px solid #334155; background: ${s.codeStyle === 'default' ? '#4f46e5' : '#1e293b'}; color: ${s.codeStyle === 'default' ? 'white' : '#cbd5e1'}; font-size: 0.8125rem; cursor: pointer; transition: all 0.2s;">Default</button> <button id="tabFullCode" style="padding: 0.625rem; border-radius: 0.5rem; border: 1px solid #334155; background: ${s.codeStyle === 'fullCode' ? '#4f46e5' : '#1e293b'}; color: ${s.codeStyle === 'fullCode' ? 'white' : '#cbd5e1'}; font-size: 0.8125rem; cursor: pointer; transition: all 0.2s;">Full Code</button> <button id="tabSnippets" style="padding: 0.625rem; border-radius: 0.5rem; border: 1px solid #334155; background: ${s.codeStyle === 'snippets' ? '#4f46e5' : '#1e293b'}; color: ${s.codeStyle === 'snippets' ? 'white' : '#cbd5e1'}; font-size: 0.8125rem; cursor: pointer; transition: all 0.2s;">Snippets</button> <button id="tabChunked" style="padding: 0.625rem; border-radius: 0.5rem; border: 1px solid #334155; background: ${s.codeStyle === 'chunked' ? '#4f46e5' : '#1e293b'}; color: ${s.codeStyle === 'chunked' ? 'white' : '#cbd5e1'}; font-size: 0.8125rem; cursor: pointer; transition: all 0.2s;">Chunked</button> </div> <div id="promptDefault" style="display: ${s.codeStyle === 'default' ? 'block' : 'none'}; padding: 0.75rem; border-radius: 0.5rem; background: #1e293b; font-size: 0.8125rem; color: #cbd5e1;"> <strong style="color: #e2e8f0;">Default:</strong> Normal responses with code in markdown blocks when helpful. </div> <div id="promptFullCode" style="display: ${s.codeStyle === 'fullCode' ? 'block' : 'none'};"> <div style="padding: 0.75rem; border-radius: 0.5rem; background: #1e293b; font-size: 0.8125rem; color: #cbd5e1; margin-bottom: 0.5rem;"> <strong style="color: #e2e8f0;">Full Code:</strong> Always provide complete, working code examples. </div> <textarea id="fullCodePrompt" rows="3" placeholder="Custom prompt for full code style..." style="width: 100%; padding: 0.625rem; border-radius: 0.5rem; border: 1px solid #334155; background: #1e293b; color: #f1f5f9; font-size: 0.8125rem; resize: vertical;">${s.fullCodePrompt || ''}</textarea> </div> <div id="promptSnippets" style="display: ${s.codeStyle === 'snippets' ? 'block' : 'none'};"> <div style="padding: 0.75rem; border-radius: 0.5rem; background: #1e293b; font-size: 0.8125rem; color: #cbd5e1; margin-bottom: 0.5rem;"> <strong style="color: #e2e8f0;">Snippets:</strong> Focus on concise code snippets and key changes only. </div> <textarea id="snippetsPrompt" rows="3" placeholder="Custom prompt for snippets style..." style="width: 100%; padding: 0.625rem; border-radius: 0.5rem; border: 1px solid #334155; background: #1e293b; color: #f1f5f9; font-size: 0.8125rem; resize: vertical;">${s.snippetsPrompt || ''}</textarea> </div> <div id="promptChunked" style="display: ${s.codeStyle === 'chunked' ? 'block' : 'none'};"> <div style="padding: 0.75rem; border-radius: 0.5rem; background: #1e293b; font-size: 0.8125rem; color: #cbd5e1; margin-bottom: 0.5rem;"> <strong style="color: #e2e8f0;">Chunked:</strong> Break code into manageable chunks to fit token limits. </div> <textarea id="chunkedPrompt" rows="3" placeholder="Custom prompt for chunked style..." style="width: 100%; padding: 0.625rem; border-radius: 0.5rem; border: 1px solid #334155; background: #1e293b; color: #f1f5f9; font-size: 0.8125rem; resize: vertical;">${s.chunkedPrompt || ''}</textarea> </div> <!-- Continuation template (used by Continue button) --> <div id="promptContinue" style="margin-top: 1rem;"> <div style="padding: 0.75rem; border-radius: 0.5rem; background: #111827; font-size: 0.8125rem; color: #cbd5e1; margin-bottom: 0.5rem;"> <strong style="color: #e2e8f0;">Continuation Prompt Template:</strong> This template is used when you click <em>Continue</em>. The special token <code>{{'{{'}}TAIL{{'}}'}}</code> will be replaced with the last part of the previous assistant output. </div> <textarea id="continuePrompt" rows="6" placeholder="Continuation prompt template (use {{TAIL}} where the tail should go)" style="width: 100%; padding: 0.625rem; border-radius: 0.5rem; border: 1px solid #334155; background: #0b1220; color: #f1f5f9; font-size: 0.8125rem; resize: vertical;">${s.continuePrompt || ''}</textarea> <div style="margin-top: 0.5rem; font-size: 0.75rem; color: #94a3b8;"> Tip: Keep temperature low for continuation. Example placeholders: <code>&lt;TAIL&gt;{{'{{'}}TAIL{{'}}'}}&lt;/TAIL&gt;</code> </div> </div> </div> <div style="display: flex; flex-wrap: wrap; gap: 1rem; margin-bottom: 1.5rem;"> <label style="display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; color: #cbd5e1;"> <input id="settingsArtifacts" type="checkbox" ${s.includeArtifacts ? 'checked' : ''} style="width: 18px; height: 18px;"> Include artifacts from session </label> <label style="display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; color: #cbd5e1;"> <input id="settingsJson" type="checkbox" ${s.jsonFormat ? 'checked' : ''} style="width: 18px; height: 18px;"> Response JSON </label> <label style="display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; color: #cbd5e1;"> <input id="settingsDebug" type="checkbox" ${s.debugMode ? 'checked' : ''} style="width: 18px; height: 18px;"> Debug Mode (show raw response) </label> </div> <div style="padding-top: 1rem; border-top: 1px solid #334155; font-size: 0.75rem; color: #94a3b8;"> <p style="margin: 0;">Settings are saved automatically to localStorage.</p> </div> </div> `; } function setupSettingsHandlers(container) { const model = container.querySelector('#settingsModel'); const maxTokens = container.querySelector('#settingsMaxTokens'); const maxTokensDisplay = container.querySelector('#maxTokensDisplay'); const temperature = container.querySelector('#settingsTemperature'); const temperatureDisplay = container.querySelector('#temperatureDisplay'); const forceTemp = container.querySelector('#settingsForceTemp'); const system = container.querySelector('#settingsSystem'); const artifacts = container.querySelector('#settingsArtifacts'); const json = container.querySelector('#settingsJson'); const debug = container.querySelector('#settingsDebug'); const fullCodePrompt = container.querySelector('#fullCodePrompt'); const snippetsPrompt = container.querySelector('#snippetsPrompt'); const chunkedPrompt = container.querySelector('#chunkedPrompt'); const continuePrompt = container.querySelector('#continuePrompt'); const tabDefault = container.querySelector('#tabDefault'); const tabFullCode = container.querySelector('#tabFullCode'); const tabSnippets = container.querySelector('#tabSnippets'); const tabChunked = container.querySelector('#tabChunked'); const promptDefault = container.querySelector('#promptDefault'); const promptFullCode = container.querySelector('#promptFullCode'); const promptSnippets = container.querySelector('#promptSnippets'); const promptChunked = container.querySelector('#promptChunked'); const btnBackToDefault = container.querySelector('#btnBackToDefault'); const btnFullCodeLikeChunked = container.querySelector('#btnFullCodeLikeChunked'); const btnUseChunkedPrompt = container.querySelector('#btnUseChunkedPrompt'); const btnUseSnippetsPrompt = container.querySelector('#btnUseSnippetsPrompt'); const btnUseContinuePrompt = container.querySelector('#btnUseContinuePrompt'); function saveSettings() { if (App.state && App.saveState) App.saveState(App.state); } function setActiveTab(style) { App.state.settings.codeStyle = style; [tabDefault, tabFullCode, tabSnippets, tabChunked].forEach(btn => { btn.style.background = '#1e293b'; btn.style.color = '#cbd5e1'; }); [promptDefault, promptFullCode, promptSnippets, promptChunked].forEach(p => p.style.display = 'none'); const activeBtn = { default: tabDefault, fullCode: tabFullCode, snippets: tabSnippets, chunked: tabChunked }[style]; const activePrompt = { default: promptDefault, fullCode: promptFullCode, snippets: promptSnippets, chunked: promptChunked }[style]; activeBtn.style.background = '#4f46e5'; activeBtn.style.color = 'white'; activePrompt.style.display = 'block'; saveSettings(); } function applyRecommended(which) { if (which === 'chunked') { if (chunkedPrompt) chunkedPrompt.value = RECOMMENDED.chunkedPrompt; App.state.settings.chunkedPrompt = RECOMMENDED.chunkedPrompt; setActiveTab('chunked'); } else if (which === 'snippets') { if (snippetsPrompt) snippetsPrompt.value = RECOMMENDED.snippetsPrompt; App.state.settings.snippetsPrompt = RECOMMENDED.snippetsPrompt; setActiveTab('snippets'); } else if (which === 'fullCode') { if (fullCodePrompt) fullCodePrompt.value = RECOMMENDED.fullCodePrompt; App.state.settings.fullCodePrompt = RECOMMENDED.fullCodePrompt; setActiveTab('fullCode'); } else if (which === 'continue') { if (continuePrompt) continuePrompt.value = RECOMMENDED.continuePrompt; App.state.settings.continuePrompt = RECOMMENDED.continuePrompt; } saveSettings(); } // Event listeners model.addEventListener('change', () => { App.state.settings.model = model.value; saveSettings(); }); maxTokens.addEventListener('input', () => { maxTokensDisplay.textContent = maxTokens.value; App.state.settings.maxTokens = parseInt(maxTokens.value); saveSettings(); }); temperature.addEventListener('input', () => { temperatureDisplay.textContent = temperature.value; App.state.settings.temperature = parseFloat(temperature.value); saveSettings(); }); forceTemp.addEventListener('change', () => { App.state.settings.forceTemperature = forceTemp.checked; saveSettings(); }); system.addEventListener('input', () => { App.state.settings.system = system.value; saveSettings(); }); artifacts.addEventListener('change', () => { App.state.settings.includeArtifacts = artifacts.checked; saveSettings(); }); json.addEventListener('change', () => { App.state.settings.jsonFormat = json.checked; saveSettings(); }); debug.addEventListener('change', () => { App.state.settings.debugMode = debug.checked; saveSettings(); }); if (fullCodePrompt) fullCodePrompt.addEventListener('input', () => { App.state.settings.fullCodePrompt = fullCodePrompt.value; saveSettings(); }); if (snippetsPrompt) snippetsPrompt.addEventListener('input', () => { App.state.settings.snippetsPrompt = snippetsPrompt.value; saveSettings(); }); if (chunkedPrompt) chunkedPrompt.addEventListener('input', () => { App.state.settings.chunkedPrompt = chunkedPrompt.value; saveSettings(); }); if (continuePrompt) continuePrompt.addEventListener('input', () => { App.state.settings.continuePrompt = continuePrompt.value; saveSettings(); }); tabDefault.addEventListener('click', () => setActiveTab('default')); tabFullCode.addEventListener('click', () => setActiveTab('fullCode')); tabSnippets.addEventListener('click', () => setActiveTab('snippets')); tabChunked.addEventListener('click', () => setActiveTab('chunked')); // Quick buttons btnBackToDefault.addEventListener('click', () => setActiveTab('default')); btnFullCodeLikeChunked.addEventListener('click', () => applyRecommended('fullCode')); btnUseChunkedPrompt.addEventListener('click', () => applyRecommended('chunked')); btnUseSnippetsPrompt.addEventListener('click', () => applyRecommended('snippets')); btnUseContinuePrompt.addEventListener('click', () => applyRecommended('continue')); } window.AppItems.push({ title: 'Settings', html: generateSettingsHTML(), onRender: setupSettingsHandlers }); console.log('[Settings] Module registered'); })();