| |
| document.addEventListener('DOMContentLoaded', async () => { |
| |
| for (let attempt = 0; attempt < 5; attempt++) { |
| try { |
| const configResp = await fetch('/api/config'); |
| const config = await configResp.json(); |
| IS_MULTI_USER = config.multiUser; |
| if (config.multiUser && !SESSION_ID) { |
| await showUsernameOverlay(); |
| } |
| break; |
| } catch (e) { |
| if (attempt < 4) { |
| await new Promise(r => setTimeout(r, 1000)); |
| } |
| |
| } |
| } |
|
|
| |
| try { |
| const agentsResp = await apiFetch('/api/agents'); |
| const agentsData = await agentsResp.json(); |
| for (const agent of agentsData.agents) { |
| AGENT_REGISTRY[agent.key] = agent; |
| } |
| } catch (e) { |
| console.error('Failed to fetch agent registry, using fallback'); |
| |
| AGENT_REGISTRY = { |
| command: { label: 'MAIN', hasCounter: false, inMenu: false, inLauncher: false, placeholder: 'Enter message...' }, |
| agent: { label: 'AGENT', hasCounter: true, inMenu: true, inLauncher: true, placeholder: 'Enter message...' }, |
| code: { label: 'CODE', hasCounter: true, inMenu: true, inLauncher: true, placeholder: 'Enter message...' }, |
| research: { label: 'RESEARCH', hasCounter: true, inMenu: true, inLauncher: true, placeholder: 'Enter message...' }, |
| image: { label: 'IMAGE', hasCounter: true, inMenu: true, inLauncher: true, placeholder: 'Describe an image or paste a URL...' }, |
| }; |
| } |
| |
| settings.agents = Object.fromEntries(Object.keys(AGENT_REGISTRY).map(k => [k, ''])); |
|
|
| await loadSettings(); |
| applyTheme(settings.themeColor || 'forest'); |
| initializeEventListeners(); |
| initializeSessionListeners(); |
| updateUserIndicator(); |
|
|
| |
| const sessionsData = await fetchSessions(); |
| showSessionSelector(sessionsData.sessions); |
|
|
| |
| requestAnimationFrame(() => updateTimelineLines()); |
| }); |
|
|
| |
| |
| |
|
|
| function renderNewTabMenu() { |
| const menu = document.getElementById('newTabMenu'); |
| if (!menu) return; |
| menu.innerHTML = ''; |
| for (const [key, agent] of Object.entries(AGENT_REGISTRY)) { |
| if (!agent.inMenu) continue; |
| const item = document.createElement('div'); |
| item.className = 'menu-item'; |
| item.dataset.type = key; |
| item.textContent = agent.label; |
| menu.appendChild(item); |
| } |
| } |
|
|
| function renderLauncherButtons() { |
| const container = document.getElementById('launcherButtons'); |
| if (!container) return; |
| |
| const debugBtn = container.querySelector('#debugBtn'); |
| for (const [key, agent] of Object.entries(AGENT_REGISTRY)) { |
| if (!agent.inLauncher) continue; |
| const btn = document.createElement('button'); |
| btn.className = 'launcher-btn'; |
| btn.dataset.type = key; |
| btn.textContent = agent.label; |
| container.insertBefore(btn, debugBtn); |
| } |
| } |
|
|
| function renderAgentModelSelectors() { |
| const grid = document.getElementById('agentModelsGrid'); |
| if (!grid) return; |
| grid.innerHTML = ''; |
| for (const [key, agent] of Object.entries(AGENT_REGISTRY)) { |
| const label = document.createElement('label'); |
| label.textContent = `${agent.label}:`; |
| const select = document.createElement('select'); |
| select.id = `setting-agent-${key}`; |
| select.className = 'settings-select'; |
| grid.appendChild(label); |
| grid.appendChild(select); |
| } |
| } |
|
|
| function initializeEventListeners() { |
| |
| renderLauncherButtons(); |
| renderNewTabMenu(); |
| renderAgentModelSelectors(); |
|
|
| |
| document.querySelectorAll('.launcher-btn').forEach(btn => { |
| btn.addEventListener('click', (e) => { |
| e.stopPropagation(); |
| const type = btn.dataset.type; |
| createAgentTab(type); |
| }); |
| }); |
|
|
| |
| const commandContent = document.querySelector('.tab-content[data-content-id="0"]'); |
| if (commandContent) { |
| setupInputListeners(commandContent, 0); |
| } |
|
|
| |
| const compactViewCheckbox = document.getElementById('compactViewCheckbox'); |
| const collapseAgentsCheckbox = document.getElementById('collapseAgentsCheckbox'); |
| const collapseToolsCheckbox = document.getElementById('collapseToolsCheckbox'); |
|
|
| |
| if (compactViewCheckbox) { |
| compactViewCheckbox.addEventListener('change', () => { |
| const compact = compactViewCheckbox.checked; |
| if (compact) { |
| |
| Object.entries(timelineData).forEach(([id, data]) => { |
| if (data.parentTabId !== null) { |
| collapsedAgents.add(String(id)); |
| } |
| }); |
| showAllTurns = false; |
| } else { |
| collapsedAgents.clear(); |
| showAllTurns = true; |
| } |
| renderTimeline(); |
| }); |
| } |
|
|
| |
| if (collapseAgentsCheckbox) { |
| collapseAgentsCheckbox.addEventListener('change', () => { |
| const collapse = collapseAgentsCheckbox.checked; |
| document.querySelectorAll('.action-widget').forEach(w => { |
| const toggle = w.querySelector('.widget-collapse-toggle'); |
| if (collapse) { |
| w.classList.add('collapsed'); |
| if (toggle) toggle.classList.add('collapsed'); |
| } else { |
| w.classList.remove('collapsed'); |
| if (toggle) toggle.classList.remove('collapsed'); |
| } |
| }); |
| }); |
| } |
|
|
| |
| if (collapseToolsCheckbox) { |
| collapseToolsCheckbox.addEventListener('change', () => { |
| const collapse = collapseToolsCheckbox.checked; |
| document.querySelectorAll('.tool-cell').forEach(w => { |
| const toggle = w.querySelector('.widget-collapse-toggle'); |
| if (collapse) { |
| w.classList.add('collapsed'); |
| if (toggle) toggle.classList.add('collapsed'); |
| } else { |
| w.classList.remove('collapsed'); |
| if (toggle) toggle.classList.remove('collapsed'); |
| } |
| }); |
| }); |
| } |
|
|
| |
| const newTabBtn = document.getElementById('newTabBtn'); |
| const newTabMenu = document.getElementById('newTabMenu'); |
|
|
| if (newTabBtn && newTabMenu) { |
| newTabBtn.addEventListener('click', (e) => { |
| e.stopPropagation(); |
| e.preventDefault(); |
|
|
| |
| const rect = newTabBtn.getBoundingClientRect(); |
| newTabMenu.style.top = `${rect.bottom}px`; |
| newTabMenu.style.left = `${rect.left}px`; |
|
|
| newTabMenu.classList.toggle('active'); |
| }); |
| } |
|
|
| |
| document.addEventListener('click', (e) => { |
| if (!e.target.closest('.new-tab-wrapper')) { |
| newTabMenu.classList.remove('active'); |
| } |
| }); |
|
|
| |
| document.querySelectorAll('.menu-item').forEach(item => { |
| item.addEventListener('click', () => { |
| const type = item.dataset.type; |
| createAgentTab(type); |
| newTabMenu.classList.remove('active'); |
| }); |
| }); |
|
|
| |
| document.addEventListener('click', (e) => { |
| const tab = e.target.closest('.tab'); |
| if (tab && !e.target.closest('.new-tab-wrapper')) { |
| if (e.target.classList.contains('tab-close')) { |
| closeTab(parseInt(tab.dataset.tabId)); |
| } else { |
| switchToTab(parseInt(tab.dataset.tabId)); |
| } |
| } |
| }); |
|
|
| |
| |
|
|
| |
| const saveSettingsBtn = document.getElementById('saveSettingsBtn'); |
| if (saveSettingsBtn) { |
| saveSettingsBtn.addEventListener('click', () => { |
| saveSettings(); |
| }); |
| } |
|
|
| |
| const cancelSettingsBtn = document.getElementById('cancelSettingsBtn'); |
| if (cancelSettingsBtn) { |
| cancelSettingsBtn.addEventListener('click', () => closeAllPanels()); |
| } |
|
|
| |
| const themePicker = document.getElementById('theme-color-picker'); |
| if (themePicker) { |
| themePicker.addEventListener('click', (e) => { |
| const themeOption = e.target.closest('.theme-option'); |
| if (themeOption) { |
| |
| themePicker.querySelectorAll('.theme-option').forEach(opt => { |
| opt.classList.remove('selected'); |
| }); |
| |
| themeOption.classList.add('selected'); |
| |
| const themeValue = themeOption.dataset.theme; |
| document.getElementById('setting-theme-color').value = themeValue; |
| } |
| }); |
| } |
|
|
| |
| document.addEventListener('click', (e) => { |
| const header = e.target.closest('.settings-group-header'); |
| if (!header) return; |
| const group = header.closest('.settings-group'); |
| if (!group) return; |
| group.classList.toggle('collapsed'); |
| const toggle = header.querySelector('.widget-collapse-toggle'); |
| if (toggle) toggle.classList.toggle('collapsed'); |
| }); |
|
|
| |
| document.addEventListener('dblclick', (e) => { |
| const toggle = e.target.closest('.widget-collapse-toggle'); |
| if (!toggle) return; |
| e.stopPropagation(); |
| const chatContainer = toggle.closest('.chat-container'); |
| if (!chatContainer) return; |
| const widgets = chatContainer.querySelectorAll('.tool-cell, .code-cell, .action-widget'); |
| if (widgets.length === 0) return; |
| |
| const clickedWidget = toggle.closest('.tool-cell, .code-cell, .action-widget'); |
| const shouldCollapse = !clickedWidget?.classList.contains('collapsed'); |
| widgets.forEach(w => { |
| w.classList.toggle('collapsed', shouldCollapse); |
| const t = w.querySelector('.widget-collapse-toggle'); |
| if (t) t.classList.toggle('collapsed', shouldCollapse); |
| }); |
| }); |
|
|
| |
| const sidebar = document.getElementById('agentsSidebar'); |
| const resizeHandle = document.getElementById('sidebarResizeHandle'); |
| if (sidebar && resizeHandle) { |
| const savedWidth = localStorage.getItem('agentui_sidebar_width'); |
| if (savedWidth) { |
| const w = parseInt(savedWidth); |
| if (w >= 140 && w <= 400) { |
| sidebar.style.setProperty('--sidebar-width', w + 'px'); |
| sidebar.style.width = w + 'px'; |
| } |
| } |
|
|
| let dragging = false; |
| resizeHandle.addEventListener('mousedown', (e) => { |
| e.preventDefault(); |
| dragging = true; |
| resizeHandle.classList.add('dragging'); |
| document.body.style.cursor = 'col-resize'; |
| document.body.style.userSelect = 'none'; |
| }); |
| document.addEventListener('mousemove', (e) => { |
| if (!dragging) return; |
| const w = Math.min(400, Math.max(140, e.clientX)); |
| sidebar.style.setProperty('--sidebar-width', w + 'px'); |
| sidebar.style.width = w + 'px'; |
| }); |
| document.addEventListener('mouseup', () => { |
| if (!dragging) return; |
| dragging = false; |
| resizeHandle.classList.remove('dragging'); |
| document.body.style.cursor = ''; |
| document.body.style.userSelect = ''; |
| const w = parseInt(sidebar.style.width); |
| if (w) localStorage.setItem('agentui_sidebar_width', w); |
| }); |
| } |
| } |
|
|