/** * THE VAULT (v4.1) — High-Fidelity UX Engine * Senior-level logic synchronization for ContentGuardEnv. */ const app = { ws: null, currentEpisodeId: null, currentTask: null, terminalActiveLine: null, typewriterTimeout: null, isAutoTraining: false, autoRunAfterReset: false, episodeDone: false, oversightStickToBottom: true, metrics: { count: 0, sumReward: 0 }, scrollPending: false, activeTab: 'arena', hasStartedEpisode: false, historyEntries: [], historyLimit: 80, historyStorageKey: 'contentguard_history_v1', activeEpisodeRecord: null, streamLineBuffer: '', init: function() { // Orchestrate the "Breathe-in" Sequence this.connectWS(); this.initVisuals(); this.loadSettings(); this.bindHotkeys(); this.bindOversightViewport(); this.loadHistory(); this.switchTab('arena'); this.renderHistory(); window.addEventListener('resize', () => { this.scrollOversightToBottom(true); if (this.activeTab === 'history') { this.drawAccuracyChart(); } }); // Add staggered fade-in classes to UI blocks document.querySelectorAll('.sidebar, .topbar, .card').forEach((el, i) => { el.style.opacity = '0'; setTimeout(() => { el.style.transition = 'opacity 0.8s var(--ease-out), transform 0.8s var(--ease-out)'; el.style.opacity = '1'; el.style.transform = 'translateY(0)'; }, 100 * i); }); }, bindHotkeys: function() { document.addEventListener('keydown', (event) => { if (event.key !== '/' || event.ctrlKey || event.metaKey || event.altKey) return; const target = event.target; const tag = target && target.tagName ? target.tagName.toLowerCase() : ''; if (target && (target.isContentEditable || tag === 'input' || tag === 'textarea' || tag === 'select')) return; const modal = document.getElementById('settings-modal'); if (modal && modal.style.display === 'flex') return; event.preventDefault(); this.quickCycleEpisode(); }); }, bindOversightViewport: function() { const term = document.getElementById('terminal-output'); if (!term) return; this.oversightStickToBottom = true; term.addEventListener('scroll', () => { const distanceFromBottom = term.scrollHeight - term.scrollTop - term.clientHeight; this.oversightStickToBottom = distanceFromBottom < 36; }); }, scrollOversightToBottom: function(force) { const term = document.getElementById('terminal-output'); if (!term) return; if (force || this.oversightStickToBottom) { term.scrollTop = term.scrollHeight; } }, quickCycleEpisode: function() { if (!this.currentTask) { this.terminalPrint('NOTICE: Select an environment tier before quick-cycle (/).'); return; } if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { this.terminalPrint('WARNING: Gateway link unavailable. Wait for LINK ACTIVE.'); return; } const overlay = document.getElementById('reward-overlay'); if (overlay) overlay.style.display = 'none'; this.terminalPrint('LOG: Quick-cycle trigger received (/). Starting next episode...'); if (this.isAutoTraining) { this.autoRunAfterReset = true; } this.startEpisode(this.currentTask, { preserveAutoRun: this.isAutoTraining }); }, connectWS: function() { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; this.ws = new WebSocket(`${protocol}//${window.location.host}/ws`); this.ws.onopen = () => { const ind = document.getElementById('status-indicator'); const txt = document.getElementById('status-text'); if (ind) ind.classList.add('connected'); if (txt) txt.textContent = 'LINK ACTIVE'; this.terminalPrint("SYSTEM: ContentGuard Secure Encryption Handshake Verified."); }; this.ws.onclose = () => { const ind = document.getElementById('status-indicator'); const txt = document.getElementById('status-text'); if (ind) ind.classList.remove('connected'); if (txt) txt.textContent = 'LINK DISCONNECTED'; this.terminalPrint("WARNING: Secure link severed. Attempting heartbeat reconnect..."); setTimeout(() => this.connectWS(), 3000); }; this.ws.onmessage = (e) => { let data; try { data = JSON.parse(e.data); } catch (_) { this.terminalPrint('[ALERT] Invalid telemetry packet received from gateway.'); return; } if (data.type === 'reset') { this.handleReset(data.observation); } else if (data.type === 'stream') { this.handleStreamChunk(data.content); } else if (data.type === 'step') { this.handleStep(data.result); } else if (data.type === 'error') { this.handleServerError(data.message || 'Unspecified gateway error.'); } }; }, // ===== OPERATIONAL FLOW ===== switchTab: function(tabName) { const nextTab = tabName === 'history' ? 'history' : 'arena'; this.activeTab = nextTab; document.querySelectorAll('.workspace-tab').forEach(btn => { btn.classList.toggle('active', btn.dataset.tab === nextTab); }); const landing = document.getElementById('landing-page'); const main = document.getElementById('main-interface'); const history = document.getElementById('history-page'); if (nextTab === 'history') { if (landing) landing.style.display = 'none'; if (main) main.style.display = 'none'; if (history) history.style.display = 'block'; this.renderHistory(); requestAnimationFrame(() => this.drawAccuracyChart()); return; } if (history) history.style.display = 'none'; if (this.hasStartedEpisode) { if (landing) landing.style.display = 'none'; if (main) main.style.display = 'grid'; } else { if (landing) landing.style.display = 'block'; if (main) main.style.display = 'none'; } this.scrollOversightToBottom(true); }, loadHistory: function() { try { const raw = sessionStorage.getItem(this.historyStorageKey); if (!raw) { this.updateMetricsFromHistory(); return; } const parsed = JSON.parse(raw); if (Array.isArray(parsed)) { this.historyEntries = parsed .filter(entry => entry && typeof entry === 'object') .slice(0, this.historyLimit) .map(entry => ({ timestamp: entry.timestamp || '', episodeId: entry.episodeId || 'n/a', postId: entry.postId || 'unknown', taskId: entry.taskId || '', taskLabel: entry.taskLabel || 'Unknown Tier', prediction: entry.prediction || 'Not captured', score: Number(entry.score) || 0, feedback: entry.feedback || '', logs: entry.logs || '' })); } } catch (_) { this.historyEntries = []; } this.updateMetricsFromHistory(); }, saveHistory: function() { try { sessionStorage.setItem(this.historyStorageKey, JSON.stringify(this.historyEntries)); } catch (_) { // If storage is unavailable, continue with in-memory history only. } }, updateMetricsFromHistory: function() { const count = this.historyEntries.length; const sumReward = this.historyEntries.reduce((acc, entry) => acc + (Number(entry.score) || 0), 0); this.metrics.count = count; this.metrics.sumReward = sumReward; const hudEpisodes = document.getElementById('hud-episodes'); const hudAccuracy = document.getElementById('hud-accuracy'); if (hudEpisodes) hudEpisodes.textContent = String(count); if (hudAccuracy) { const avg = count > 0 ? (sumReward / count) * 100 : 0; hudAccuracy.textContent = `${avg.toFixed(1)}%`; } const historySummary = document.getElementById('history-summary'); if (historySummary) { if (count === 0) { historySummary.textContent = 'No Episodes'; } else { const avg = (sumReward / count) * 100; historySummary.textContent = `${count} Episodes · Avg ${avg.toFixed(1)}%`; } } }, startEpisodeRecord: function(taskId) { this.activeEpisodeRecord = { episodeId: null, postId: null, taskId: taskId || this.currentTask || '', prediction: '', logs: '' }; this.streamLineBuffer = ''; }, appendEpisodeLog: function(content) { if (!this.activeEpisodeRecord || !content) return; const existing = this.activeEpisodeRecord.logs || ''; const merged = `${existing}${content}`; const maxLen = 18000; this.activeEpisodeRecord.logs = merged.length > maxLen ? merged.slice(merged.length - maxLen) : merged; }, capturePredictionFromStream: function(content) { if (!content) return; this.streamLineBuffer += content; let newlineIdx = this.streamLineBuffer.indexOf('\n'); while (newlineIdx !== -1) { const line = this.streamLineBuffer.slice(0, newlineIdx); this.inspectStreamLine(line); this.streamLineBuffer = this.streamLineBuffer.slice(newlineIdx + 1); newlineIdx = this.streamLineBuffer.indexOf('\n'); } }, inspectStreamLine: function(rawLine) { const line = (rawLine || '').trim(); if (!line) return; const marker = '[STEP] Policy Ingested:'; const idx = line.indexOf(marker); if (idx !== -1) { const prediction = line.slice(idx + marker.length).trim(); if (prediction) this.setEpisodePrediction(prediction); } }, setEpisodePrediction: function(predictionValue) { if (!this.activeEpisodeRecord) return; this.activeEpisodeRecord.prediction = this.stringifyPrediction(predictionValue); }, stringifyPrediction: function(predictionValue) { if (predictionValue === null || predictionValue === undefined) return 'Not captured'; if (typeof predictionValue === 'string') { const trimmed = predictionValue.trim(); return trimmed || 'Not captured'; } try { return JSON.stringify(predictionValue, null, 2); } catch (_) { return String(predictionValue); } }, escapeHTML: function(value) { return String(value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); }, recordHistoryEntry: function(result, reward, feedback) { if (this.streamLineBuffer.trim()) { this.inspectStreamLine(this.streamLineBuffer); this.streamLineBuffer = ''; } const episode = this.activeEpisodeRecord || {}; const taskLabels = { easy: 'Tier I: Detection', medium: 'Tier II: Action', hard: 'Tier III: Adjudication' }; let prediction = episode.prediction; if (!prediction && result && result.info && result.info.ground_truth && result.info.ground_truth.action) { prediction = `Not captured. Ground truth action: ${result.info.ground_truth.action}`; } if (!prediction) prediction = 'Not captured'; const normalizedReward = Number.isFinite(Number(reward)) ? Number(reward) : 0; const taskId = episode.taskId || this.currentTask || ''; const entry = { timestamp: new Date().toLocaleString(), episodeId: episode.episodeId || this.currentEpisodeId || 'n/a', postId: episode.postId || 'unknown', taskId: taskId, taskLabel: taskLabels[taskId] || taskId || 'Unknown Tier', prediction: prediction, score: normalizedReward, feedback: feedback || '', logs: (episode.logs || '').trim() || 'No logs captured for this episode.' }; this.historyEntries.unshift(entry); if (this.historyEntries.length > this.historyLimit) { this.historyEntries = this.historyEntries.slice(0, this.historyLimit); } this.saveHistory(); this.updateMetricsFromHistory(); this.renderHistory(); }, renderHistory: function() { const list = document.getElementById('history-list'); if (!list) return; if (!this.historyEntries.length) { list.innerHTML = '
No episodes recorded yet. Run an episode in Arena mode and results will appear here.
'; if (this.activeTab === 'history') this.drawAccuracyChart(); return; } list.innerHTML = this.historyEntries.map((entry, index) => { const score = Number(entry.score) || 0; const scoreColor = score >= 0.8 ? 'var(--emerald-500)' : (score >= 0.4 ? 'var(--amber-500)' : 'var(--rose-500)'); const predictionSafe = this.escapeHTML(entry.prediction || 'Not captured'); const feedbackSafe = this.escapeHTML(entry.feedback || 'No feedback available.'); const rawLogs = entry.logs || ''; const clippedLogs = rawLogs.length > 1800 ? `${rawLogs.slice(0, 1800)}\n...` : rawLogs; const logsSafe = this.escapeHTML(clippedLogs); return `

#${this.historyEntries.length - index} · ${this.escapeHTML(entry.taskLabel)}

${score.toFixed(4)}

${this.escapeHTML(entry.timestamp)} · Episode ${this.escapeHTML(entry.episodeId)} · Post ${this.escapeHTML(entry.postId)}

Prediction
${predictionSafe}
Feedback
${feedbackSafe}
Logs
${logsSafe}
`; }).join(''); if (this.activeTab === 'history') this.drawAccuracyChart(); }, drawAccuracyChart: function() { const canvas = document.getElementById('accuracy-chart'); if (!canvas) return; const cssWidth = Math.floor(canvas.clientWidth || 900); const cssHeight = Math.floor(canvas.clientHeight || 240); if (cssWidth <= 0 || cssHeight <= 0) return; const dpr = window.devicePixelRatio || 1; canvas.width = Math.max(1, Math.floor(cssWidth * dpr)); canvas.height = Math.max(1, Math.floor(cssHeight * dpr)); const ctx = canvas.getContext('2d'); if (!ctx) return; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); ctx.clearRect(0, 0, cssWidth, cssHeight); const chartPad = { top: 16, right: 20, bottom: 30, left: 44 }; const chartWidth = cssWidth - chartPad.left - chartPad.right; const chartHeight = cssHeight - chartPad.top - chartPad.bottom; ctx.strokeStyle = 'rgba(15, 159, 155, 0.18)'; ctx.lineWidth = 1; for (let i = 0; i <= 4; i++) { const y = chartPad.top + (chartHeight / 4) * i; ctx.beginPath(); ctx.moveTo(chartPad.left, y); ctx.lineTo(chartPad.left + chartWidth, y); ctx.stroke(); } ctx.fillStyle = 'rgba(71, 85, 105, 0.75)'; ctx.font = '11px "IBM Plex Mono", monospace'; [100, 75, 50, 25, 0].forEach((label, idx) => { const y = chartPad.top + (chartHeight / 4) * idx; ctx.fillText(String(label), 10, y + 4); }); const values = this.historyEntries.slice().reverse().map(entry => { const n = Number(entry.score); const pct = Number.isFinite(n) ? n * 100 : 0; return Math.max(0, Math.min(100, pct)); }); if (!values.length) { ctx.fillStyle = 'rgba(100, 116, 139, 0.7)'; ctx.font = '12px "Sora", sans-serif'; ctx.fillText('No data yet. Complete an episode to visualize policy accuracy.', chartPad.left + 8, chartPad.top + chartHeight / 2); return; } const xForIndex = (index) => { if (values.length === 1) return chartPad.left + chartWidth / 2; return chartPad.left + (chartWidth * index) / (values.length - 1); }; const yForValue = (value) => chartPad.top + chartHeight - (value / 100) * chartHeight; ctx.strokeStyle = 'rgba(15, 159, 155, 0.95)'; ctx.lineWidth = 2.2; ctx.beginPath(); values.forEach((val, idx) => { const x = xForIndex(idx); const y = yForValue(val); if (idx === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); }); ctx.stroke(); ctx.fillStyle = 'rgba(15, 159, 155, 0.16)'; ctx.beginPath(); values.forEach((val, idx) => { const x = xForIndex(idx); const y = yForValue(val); if (idx === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); }); ctx.lineTo(xForIndex(values.length - 1), chartPad.top + chartHeight); ctx.lineTo(xForIndex(0), chartPad.top + chartHeight); ctx.closePath(); ctx.fill(); ctx.fillStyle = 'rgba(7, 126, 122, 0.95)'; values.forEach((val, idx) => { const x = xForIndex(idx); const y = yForValue(val); ctx.beginPath(); ctx.arc(x, y, 3, 0, Math.PI * 2); ctx.fill(); }); ctx.fillStyle = 'rgba(71, 85, 105, 0.75)'; ctx.font = '11px "IBM Plex Mono", monospace'; ctx.fillText(`Ep 1`, chartPad.left, cssHeight - 8); ctx.fillText(`Ep ${values.length}`, chartPad.left + chartWidth - 42, cssHeight - 8); }, clearHistory: function() { this.historyEntries = []; this.saveHistory(); this.updateMetricsFromHistory(); this.renderHistory(); this.terminalPrint('SYSTEM: Episode history has been cleared.'); }, startEpisode: function(taskId, options) { const opts = options || {}; const preserveAutoRun = opts.preserveAutoRun === true; this.currentTask = taskId; this.hasStartedEpisode = true; this.startEpisodeRecord(taskId); if (!preserveAutoRun) { this.autoRunAfterReset = false; } this.episodeDone = false; this.currentEpisodeId = null; // Update Sidebar States document.querySelectorAll('.nav-item[data-task]').forEach(btn => { btn.classList.toggle('active', btn.dataset.task === taskId); }); // Update Workspace Context const labels = { easy: 'Tier I: Detection', medium: 'Tier II: Action', hard: 'Tier III: Adjudication' }; document.getElementById('breadcrumb-task').textContent = labels[taskId] || taskId; if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { this.terminalPrint('WARNING: Gateway link is not ready. Wait for LINK ACTIVE before starting.'); return; } this.setAgentButtonsIdle(); const config = JSON.parse(sessionStorage.getItem('env_config') || '{}'); this.ws.send(JSON.stringify({ action: "reset", task_id: taskId, config: config })); // Interface Transition document.getElementById('landing-page').style.display = 'none'; if (this.activeTab === 'arena') { document.getElementById('main-interface').style.display = 'grid'; // Grid for Hub layout } document.getElementById('reward-overlay').style.display = 'none'; this.terminalPrint(`\nLOG: Resetting Environment. Module: ${taskId.toUpperCase()}`); }, handleReset: function(obs) { this.currentEpisodeId = obs.episode_id; this.episodeDone = false; const c = obs.content_case; const b = obs.policy_briefing; if (this.activeEpisodeRecord) { this.activeEpisodeRecord.episodeId = obs.episode_id; this.activeEpisodeRecord.postId = c.post_id; this.activeEpisodeRecord.taskId = obs.task_id || this.currentTask || this.activeEpisodeRecord.taskId; } // Banner Status const banner = document.getElementById('policy-alert-banner'); document.getElementById('alert-level').textContent = b.alert_level.toUpperCase(); document.getElementById('alert-topic').textContent = b.current_focus; document.getElementById('alert-summary').textContent = b.guidance_summary; // Map alert levels to colors const level = b.alert_level.toLowerCase(); banner.style.borderLeftColor = level === 'critical' ? 'var(--danger)' : level === 'elevated' ? '#f97316' : level === 'yellow' ? 'var(--warning)' : 'var(--indigo-500)'; // Metadata Pulse this.updateMetric('val-post-id', c.post_id); this.updateMetric('val-platform', c.platform); this.updateMetric('val-user-age', `${c.user_account.account_age_days}d`); this.updateMetric('val-prior-violations', c.user_account.prior_violations); this.updateMetric('val-reports', c.engagement.reports_received); this.typeWriterEffect('val-content', `"${c.content}"`, 10); this.renderActionForm(obs.action_space); this.terminalPrint(`INFO: Ingesting context payload. Case ID: ${c.post_id}`); if (this.autoRunAfterReset && this.isAutoTraining) { this.autoRunAfterReset = false; setTimeout(() => { if (this.isAutoTraining) this.runAgent(true); }, 180); } }, updateMetric: function(id, val) { const el = document.getElementById(id); if (!el) return; el.style.transition = 'none'; el.style.color = 'var(--indigo-500)'; el.textContent = val; setTimeout(() => { el.style.transition = 'color 1s var(--ease-out)'; el.style.color = ''; }, 100); }, renderActionForm: function(space) { const panel = document.getElementById('action-panel'); let html = '
'; for (const [key, prop] of Object.entries(space.properties)) { html += `
`; if (prop.enum) { html += ``; } else if (prop.type === 'string') { html += ``; } else if (prop.type === 'integer') { html += ``; } html += `
`; } html += `
`; html += ``; panel.innerHTML = html; }, submitAction: function() { if (!this.currentEpisodeId || this.episodeDone) { this.terminalPrint('NOTICE: Active episode required. Start a tier to submit a ruling.'); return; } if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { this.terminalPrint('WARNING: Gateway link is not ready.'); return; } const payload = {}; const inputs = document.querySelectorAll('[id^="input-"]'); inputs.forEach(input => { const key = input.id.replace('input-', ''); let val = input.value; if (input.type === 'number') val = parseInt(val, 10); payload[key] = val; }); this.terminalPrint(`LOG: External ruling override received. Processing payload...`); this.setEpisodePrediction(payload); this.ws.send(JSON.stringify({ action: "step", data: payload })); }, // ===== AUTONOMOUS EXECUTION ===== toggleAutoLoop: function() { this.isAutoTraining = !this.isAutoTraining; const btn = document.getElementById('btn-auto-loop'); if (this.isAutoTraining) { btn.innerHTML = ' Terminate Loop'; btn.style.background = 'var(--zinc-50)'; btn.style.color = 'var(--zinc-950)'; if (!this.currentTask) { this.stopAutoLoop('NOTICE: Pick an environment tier before enabling training loop.'); return; } if (!this.currentEpisodeId || this.episodeDone) { this.autoRunAfterReset = true; this.startEpisode(this.currentTask, { preserveAutoRun: true }); return; } this.runAgent(true); } else { this.stopAutoLoop('\nNOTICE: Autonomous training loop halted.'); } }, runAgent: function(isLooping) { if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { this.stopAutoLoop('WARNING: Gateway link unavailable. Reconnect and retry.'); return; } if (!this.currentEpisodeId || this.episodeDone) { if (isLooping && this.currentTask) { this.autoRunAfterReset = true; this.startEpisode(this.currentTask, { preserveAutoRun: true }); } else { this.terminalPrint('NOTICE: Episode finished. Start a tier to create a new case.'); } return; } this.terminalPrint(`\nINFO: AI Judge invoked for Judicial Evaluation.`); const term = document.getElementById('terminal-output'); this.terminalActiveLine = document.createElement('div'); this.terminalActiveLine.className = 'log-line active'; term.appendChild(this.terminalActiveLine); this.scrollOversightToBottom(true); document.getElementById('btn-run-agent').disabled = true; document.getElementById('btn-auto-loop').disabled = !isLooping; const config = JSON.parse(sessionStorage.getItem('env_config') || '{}'); this.ws.send(JSON.stringify({ action: "run_agent", config: config })); // Kinetic Active State document.querySelectorAll('.card').forEach(c => c.style.borderColor = 'var(--indigo-500)'); }, setAgentButtonsIdle: function() { const runBtn = document.getElementById('btn-run-agent'); const loopBtn = document.getElementById('btn-auto-loop'); if (runBtn) runBtn.disabled = false; if (loopBtn) { loopBtn.disabled = false; if (this.isAutoTraining) { loopBtn.innerHTML = ' Terminate Loop'; loopBtn.style.background = 'var(--zinc-50)'; loopBtn.style.color = 'var(--zinc-950)'; } else { loopBtn.innerHTML = ' Training Loop'; loopBtn.style.background = ''; loopBtn.style.color = ''; } } }, stopAutoLoop: function(message) { this.isAutoTraining = false; this.autoRunAfterReset = false; this.setAgentButtonsIdle(); if (message) this.terminalPrint(message); }, handleServerError: function(message) { const text = message || 'Unknown internal error'; this.terminalPrint(`[ALERT] Internal Error: ${text}`); console.error('ContentGuard Error:', text); const lowered = text.toLowerCase(); if (lowered.includes('episode finished') || lowered.includes('reset()') || lowered.includes('api key') || lowered.includes('authentication')) { this.stopAutoLoop('NOTICE: Loop paused due to gateway guard. Resetting case is required.'); } else { this.setAgentButtonsIdle(); } }, handleStreamChunk: function(content) { this.appendEpisodeLog(content); this.capturePredictionFromStream(content); if (!this.terminalActiveLine) { const term = document.getElementById('terminal-output'); this.terminalActiveLine = document.createElement('div'); this.terminalActiveLine.className = 'log-line active'; term.appendChild(this.terminalActiveLine); } this.terminalActiveLine.textContent += content; if (!this.scrollPending) { this.scrollPending = true; requestAnimationFrame(() => { this.scrollOversightToBottom(true); this.scrollPending = false; }); } }, handleStep: function(result) { if (this.terminalActiveLine) { this.terminalActiveLine.classList.remove('active'); this.terminalActiveLine = null; } this.episodeDone = true; // Reset Kinetic States document.querySelectorAll('.card').forEach(c => c.style.borderColor = ''); const scoreDisplay = document.getElementById('reward-display'); const title = document.getElementById('diagnostic-title'); const parsedReward = Number(result.reward); const rw = Number.isFinite(parsedReward) ? parsedReward : 0; const feedback = (result.info && result.info.feedback) ? result.info.feedback : ""; // --- Credential Interceptor (Vanguard Logic) --- const feedbackLower = feedback.toLowerCase(); const isAuthError = feedbackLower.includes("401") || feedbackLower.includes("invalid api key") || feedbackLower.includes("incorrect api key") || feedbackLower.includes("authentication failed"); if (isAuthError) { this.terminalPrint("ALERT: Security Handshake Failed. Halting operations."); this.stopAutoLoop(); title.textContent = "SECURITY_HANDSHAKE_FAILED"; title.style.color = "var(--rose-500)"; scoreDisplay.textContent = "FAULT"; scoreDisplay.style.color = "var(--rose-500)"; } else { title.textContent = "Judicial Alignment Captured"; title.style.color = "var(--indigo-500)"; scoreDisplay.textContent = Number.isFinite(rw) ? rw.toFixed(4) : '0.0000'; // Dynamic Grading Color if (rw >= 0.8) scoreDisplay.style.color = 'var(--emerald-500)'; else if (rw >= 0.4) scoreDisplay.style.color = 'var(--amber-500)'; else scoreDisplay.style.color = 'var(--rose-500)'; } document.getElementById('feedback-display').textContent = feedback; document.getElementById('reward-overlay').style.display = 'flex'; this.setAgentButtonsIdle(); this.recordHistoryEntry(result, rw, feedback); if (this.isAutoTraining) { setTimeout(() => { if (this.isAutoTraining) { this.closeReward(); if (this.currentTask) { this.autoRunAfterReset = true; this.startEpisode(this.currentTask, { preserveAutoRun: true }); } else { this.stopAutoLoop('NOTICE: Training loop paused because no tier is selected.'); } } }, 1800); } }, closeReward: function(silent, autoStartNext) { document.getElementById('reward-overlay').style.display = 'none'; const shouldAutoStart = !!this.currentTask && (autoStartNext === true || (!this.isAutoTraining && this.episodeDone)); if (shouldAutoStart) { this.terminalPrint('LOG: Dismiss received. Starting next episode...'); this.startEpisode(this.currentTask, { preserveAutoRun: this.isAutoTraining || this.autoRunAfterReset }); return; } if (!silent && !this.isAutoTraining) { this.terminalPrint(`LOG: Alignment evaluation captured and dismissed.`); } }, clearTerminal: function() { document.getElementById('terminal-output').innerHTML = ''; this.terminalPrint('SESSION: Buffer cleared. Awaiting telemetry...'); }, terminalPrint: function(msg) { if (this.terminalActiveLine) { this.terminalActiveLine.classList.remove('active'); this.terminalActiveLine = null; } this.appendEpisodeLog(`${msg}\n`); const term = document.getElementById('terminal-output'); const line = document.createElement('div'); line.className = 'log-line'; line.textContent = msg; term.appendChild(line); while (term.children.length > 50) term.removeChild(term.firstChild); this.scrollOversightToBottom(true); }, typeWriterEffect: function(elemId, text, speed) { if (this.typewriterTimeout) clearTimeout(this.typewriterTimeout); const el = document.getElementById(elemId); el.textContent = ''; let i = 0; const type = () => { if (i < text.length) { el.textContent += text.charAt(i); i++; this.typewriterTimeout = setTimeout(type, speed); } }; type(); }, // ===== SYSTEM VISUALS ===== initVisuals: function() { const canvas = document.getElementById('fluid-canvas'); if (!canvas) return; const ctx = canvas.getContext('2d'); let width = canvas.width = window.innerWidth; let height = canvas.height = window.innerHeight; const particles = []; window.addEventListener('resize', () => { width = canvas.width = window.innerWidth; height = canvas.height = window.innerHeight; }); for (let i = 0; i < 40; i++) { particles.push({ x: Math.random() * width, y: Math.random() * height, vx: (Math.random() - 0.5) * 0.2, vy: (Math.random() - 0.5) * 0.2, radius: Math.random() * 2 + 1, color: `rgba(99, 102, 241, ${Math.random() * 0.15})` }); } const draw = () => { ctx.clearRect(0, 0, width, height); particles.forEach(p => { p.x += p.vx; p.y += p.vy; if (p.x < 0 || p.x > width) p.vx *= -1; if (p.y < 0 || p.y > height) p.vy *= -1; ctx.beginPath(); ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2); ctx.fillStyle = p.color; ctx.fill(); }); requestAnimationFrame(draw); } draw(); }, // ===== SETTINGS MANAGEMENT ===== toggleSettings: function() { const modal = document.getElementById('settings-modal'); modal.style.display = modal.style.display === 'none' ? 'flex' : 'none'; if (modal.style.display === 'flex') this.loadSettings(); }, saveSettings: function() { const apiKey = document.getElementById('cfg-api-key').value; const baseUrl = document.getElementById('cfg-base-url').value; const model = document.getElementById('cfg-model').value; // Auto-Router Suggestion if (apiKey.startsWith('hf_') && (!baseUrl || baseUrl.includes('openai.com'))) { document.getElementById('cfg-base-url').value = "https://api-inference.huggingface.co/v1"; } const config = { api_key: apiKey, base_url: document.getElementById('cfg-base-url').value, model: document.getElementById('cfg-model').value }; sessionStorage.setItem('env_config', JSON.stringify(config)); this.terminalPrint("SYSTEM: Developer credentials synchronized and active."); this.toggleSettings(); }, clearSettings: function() { sessionStorage.removeItem('env_config'); document.getElementById('cfg-api-key').value = ''; document.getElementById('cfg-base-url').value = ''; document.getElementById('cfg-model').value = ''; this.terminalPrint("SYSTEM: All custom credentials purged."); }, loadSettings: function() { const config = JSON.parse(sessionStorage.getItem('env_config') || '{}'); if (config.api_key) document.getElementById('cfg-api-key').value = config.api_key; if (config.base_url) document.getElementById('cfg-base-url').value = config.base_url; if (config.model) document.getElementById('cfg-model').value = config.model; } }; window.onload = () => app.init();