async function renderChat() { const content = document.getElementById('pageContent'); content.innerHTML = `
Agents
opencode
Code & DevOps
Hermes
Memory & Scheduling
Gemini CLI
Research & Analysis
opencode • ready
💬
Agentic OS Chat
Select an agent on the left and start a conversation.
Each agent has different capabilities — choose the right one for your task.
opencode
`; window._currentAgent = 'opencode'; window._chatHistory = []; document.getElementById('chatInput').focus(); // Update agent status indicators try { const status = await api.getStatus(); (status.agents || []).forEach(a => { const el = document.querySelector(`.chat-agent[data-agent="${a.name}"]`); if (el) { const dot = el.querySelector('.agent-dot'); dot.className = `agent-dot ${a.status}`; } }); updateAgentStatusText(); } catch {} // Load chat history await refreshChat(); } function selectAgent(agent) { window._currentAgent = agent; document.querySelectorAll('.chat-agent').forEach(el => el.classList.remove('active')); document.querySelector(`.chat-agent[data-agent="${agent}"]`).classList.add('active'); document.getElementById('chatAgentIndicator').textContent = agent; document.getElementById('chatInput').focus(); updateAgentStatusText(); } function updateAgentStatusText() { const el = document.getElementById('chatAgentStatus'); if (el && window._currentAgent) { const agentEl = document.querySelector(`.chat-agent[data-agent="${window._currentAgent}"]`); const dot = agentEl ? agentEl.querySelector('.agent-dot').className : 'offline'; el.textContent = `${window._currentAgent} • ${dot === 'agent-dot online' ? 'online' : 'offline'}`; } } function handleChatKey(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendChatMessage(); } autoResizeTextarea(e.target); } function autoResizeTextarea(el) { el.style.height = 'auto'; el.style.height = Math.min(el.scrollHeight, 150) + 'px'; } async function sendChatMessage() { const input = document.getElementById('chatInput'); const message = input.value.trim(); if (!message) return; const agent = window._currentAgent || 'opencode'; input.value = ''; input.style.height = 'auto'; // Add user message to chat addChatMessage('user', message, agent); // Show typing indicator const typingId = showTypingIndicator(agent); try { // Client-side timeout: 200s (slightly more than Hermes' 180s backend timeout) const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 200000); const r = await api.chat(agent, message, controller); clearTimeout(timeoutId); removeTypingIndicator(typingId); addChatMessage('assistant', r.response.content, agent); // Store in local history window._chatHistory.push({ role: 'user', content: message, agent }); window._chatHistory.push({ role: 'assistant', content: r.response.content, agent }); } catch (err) { removeTypingIndicator(typingId); const msg = err.name === 'AbortError' ? 'Request timed out after 200s' : err.message; addChatMessage('assistant', `⚠ Error: ${msg}`, agent); } } function addChatMessage(role, content, agent) { const container = document.getElementById('chatMessages'); const welcome = container.querySelector('.chat-welcome'); if (welcome) welcome.style.display = 'none'; const msg = document.createElement('div'); msg.className = `chat-message ${role}`; msg.innerHTML = `
${role === 'user' ? '👤' : '🤖'}
${role === 'user' ? 'You' : agent} just now
${escapeHtml(content)}
`; container.appendChild(msg); container.scrollTop = container.scrollHeight; } function showTypingIndicator(agent) { const container = document.getElementById('chatMessages'); const id = 'typing-' + Date.now(); const div = document.createElement('div'); div.className = 'chat-message assistant'; div.id = id; div.innerHTML = `
🤖
${agent}
`; container.appendChild(div); container.scrollTop = container.scrollHeight; return id; } function removeTypingIndicator(id) { const el = document.getElementById(id); if (el) el.remove(); } async function refreshChat() { try { const data = await api.getChatHistory(); const messages = data.messages || []; window._chatHistory = messages; renderChatHistory(messages); } catch {} } function renderChatHistory(messages) { const container = document.getElementById('chatMessages'); if (!container) return; const welcome = container.querySelector('.chat-welcome'); if (welcome) welcome.style.display = 'none'; // Remove all existing messages (keep welcome) container.querySelectorAll('.chat-message').forEach(el => el.remove()); if (messages.length === 0) { if (welcome) welcome.style.display = ''; return; } messages.forEach(msg => { const div = document.createElement('div'); div.className = `chat-message ${msg.role}`; div.innerHTML = `
${msg.role === 'user' ? '👤' : '🤖'}
${msg.role === 'user' ? 'You' : msg.agent} ${timeAgo(msg.timestamp)}
${escapeHtml(msg.content)}
`; container.appendChild(div); }); container.scrollTop = container.scrollHeight; } function clearChat() { document.querySelectorAll('#chatMessages .chat-message').forEach(el => el.remove()); const welcome = document.querySelector('.chat-welcome'); if (welcome) welcome.style.display = ''; window._chatHistory = []; } function sendQuickPrompt(agent, message) { selectAgent(agent); document.getElementById('chatInput').value = message; sendChatMessage(); }