UNPKG

c9ai

Version:

Universal AI assistant with vibe-based workflows, hybrid cloud+local AI, and comprehensive tool integration

1,408 lines (1,284 loc) • 260 kB
<!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <title>c9ai - AI-Powered Development Assistant</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style> :root { --bg: #000000; --panel: #121212; --muted: #1a1a1a; --text: #ffffff; --sub: #b3b3b3; --primary: #7c83ff; --primary-ink: #ffffff; --bubble: #1a1a1a; --user: #7c83ff; --danger: #ff4d6d; --ok: #2ecc71; --border: #333333; --sidebar: #000000; } /* Light mode - clean and minimal like your test page */ [data-theme="light"] { --bg: #ffffff; --panel: #ffffff; --muted: #f5f5f5; --text: #000000; --sub: #666666; --primary: #7c83ff; --primary-ink: #ffffff; --bubble: #f9f9f9; --user: #7c83ff; --danger: #ff4d6d; --ok: #2ecc71; --border: #dddddd; --sidebar: #fafafa; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } * { box-sizing: border-box; } html, body { height: 100%; margin: 0; padding: 0; } body { font: 14px/1.5 ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, Helvetica Neue, Arial, "Apple Color Emoji", "Segoe UI Emoji"; color: var(--text); background: var(--bg); display: flex; min-height: 100vh; max-height: 100vh; overflow: hidden; } /* Sidebar Navigation */ .sidebar { width: 280px; background: var(--sidebar); border-right: 1px solid var(--border); display: flex; flex-direction: column; transition: transform 0.3s ease; } .sidebar.collapsed { transform: translateX(-100%); } .sidebar-header { padding: 16px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 12px; } .logo { font-size: 18px; font-weight: 700; background: linear-gradient(45deg, var(--primary), #b794f6); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .nav-section { padding: 16px 12px 8px 12px; } .nav-section.conversations { flex: 1; display: flex; flex-direction: column; min-height: 0; } .nav-section-title { font-size: 12px; font-weight: 600; color: var(--sub); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 8px; } .nav-item { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-radius: 8px; cursor: pointer; transition: all 0.2s; margin-bottom: 4px; font-size: 13px; } .nav-item:hover { background: var(--muted); } .nav-item.active { background: var(--primary); color: var(--primary-ink); } .conversations-list { flex: 1; min-height: 0; /* critical for flex scrolling */ overflow-y: auto; padding: 0 12px; } .conversation-item { display: flex; flex-direction: column; padding: 8px 12px; border-radius: 8px; cursor: pointer; transition: all 0.2s; margin-bottom: 4px; border: 1px solid transparent; } .conversation-item:hover { background: var(--muted); border-color: var(--border); } .conversation-item.active { background: var(--bubble); border-color: var(--primary); } .conversation-title { font-size: 13px; font-weight: 500; margin-bottom: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .conversation-preview { font-size: 11px; color: var(--sub); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .conversation-time { font-size: 10px; color: var(--sub); margin-top: 4px; } /* Main Content Area */ .main-content { flex: 1; display: flex; flex-direction: column; overflow: hidden; /* allow inner flex children to size/scroll properly */ min-height: 0; } .main-header { padding: 16px 20px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; background: var(--panel); } .view-content { flex: 1; display: flex; flex-direction: column; overflow-y: auto; min-height: 0; } .header-left { display: flex; align-items: center; gap: 12px; } .header-right { display: flex; align-items: center; gap: 8px; } .provider-switcher { display: flex; background: var(--muted); border-radius: 8px; padding: 2px; gap: 2px; } .pill { padding: 6px 12px; border: none; background: var(--muted); color: var(--sub); border-radius: 20px; cursor: pointer; font-size: 12px; font-weight: 500; transition: all 0.3s ease; border: 1px solid var(--border); } .pill.active { background: #ff6b35; color: white; border-color: #ff6b35; box-shadow: 0 0 0 2px rgba(255, 107, 53, 0.3), 0 2px 8px rgba(255, 107, 53, 0.2); font-weight: 600; transform: translateY(-1px); } .pill:hover:not(.active) { background: var(--panel); border-color: var(--primary); color: var(--text); transform: translateY(-0.5px); } /* Chat Area */ .chat-container { flex: 1; display: flex; flex-direction: column; min-height: 0; position: relative; height: 100%; } .chat-messages { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 20px; display: flex; flex-direction: column; gap: 16px; } .message { display: flex; align-items: flex-start; gap: 12px; max-width: 85%; } .message.user { align-self: flex-end; flex-direction: row-reverse; } .message-avatar { width: 32px; height: 32px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600; flex-shrink: 0; } .message.user .message-avatar { background: var(--user); color: var(--primary-ink); } .message.assistant .message-avatar { background: var(--bubble); color: var(--text); } .message-content { background: var(--bubble); padding: 12px 16px; border-radius: 16px; border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,0.1); white-space: pre-wrap; word-break: break-word; } .message-content li { list-style: inside disc; margin-left: 1rem; margin-bottom: 6px; } /* RSS card + thumbnail styles */ .message-content .rss-item { background: var(--bubble); border: 1px solid var(--border); border-radius: 12px; padding: 12px; margin: 12px 0; } .message-content .rss-thumb { width: 100%; max-width: 100%; height: auto; border-radius: 10px; display: block; margin: 6px 0 10px 0; object-fit: cover; } .message-content .rss-title { font-weight: 700; margin: 6px 0 4px 0; color: var(--text); } .message-content .rss-desc { color: var(--text); opacity: 0.9; line-height: 1.5; } .message-content .rss-meta-line { margin: 2px 0 8px 0; font-size: 13px; color: var(--sub); } .message-content .rss-meta { margin-top: 8px; font-size: 13px; color: var(--sub); display: flex; gap: 10px; align-items: center; } .message-content .rss-meta a.pill-read { text-decoration: none; border: 1px solid var(--border); padding: 4px 10px; border-radius: 999px; background: var(--muted); color: var(--text); } .message.user .message-content { background: var(--user); color: var(--primary-ink); } .message-time { font-size: 10px; color: var(--sub); margin-top: 4px; } /* Input Area */ .chat-input-container { position: sticky; bottom: 0; padding: 12px 20px; border-top: 1px solid var(--border); background: var(--panel); flex-shrink: 0; z-index: 10; margin-top: auto; } /* Small footer bar pinned at the very bottom */ .app-footer { background: var(--bg); color: var(--sub); font-size: 11px; border-top: 1px solid var(--border); padding: 6px 12px; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; } /* Debug Panel Styles */ .debug-panel { position: fixed; top: 20px; right: 20px; width: 400px; max-height: 600px; background: var(--panel); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.3); z-index: 1000; display: none; flex-direction: column; } .debug-header { padding: 12px 16px; background: var(--muted); border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; border-radius: 8px 8px 0 0; } .debug-title { font-weight: 600; font-size: 14px; color: var(--text); } .debug-close { background: none; border: none; color: var(--sub); cursor: pointer; padding: 4px; border-radius: 4px; font-size: 16px; } .debug-close:hover { background: var(--border); color: var(--text); } .debug-content { flex: 1; overflow-y: auto; padding: 12px; font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace; font-size: 12px; line-height: 1.4; } .debug-entry { margin-bottom: 8px; padding: 6px 8px; border-radius: 4px; border-left: 3px solid var(--border); } .debug-entry.info { background: rgba(124, 131, 255, 0.1); border-left-color: var(--primary); } .debug-entry.success { background: rgba(46, 204, 113, 0.1); border-left-color: var(--ok); } .debug-entry.warning { background: rgba(255, 193, 7, 0.1); border-left-color: #ffc107; } .debug-entry.error { background: rgba(255, 77, 109, 0.1); border-left-color: var(--danger); } .debug-entry.tool { background: rgba(156, 39, 176, 0.1); border-left-color: #9c27b0; } .debug-timestamp { color: var(--sub); font-size: 10px; margin-right: 8px; } .debug-icon { margin-right: 6px; } .debug-message { color: var(--text); } .debug-toggle { position: fixed; bottom: 20px; left: 20px; right: auto; width: 50px; height: 50px; border-radius: 50%; background: var(--primary); color: white; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; box-shadow: 0 2px 10px rgba(0,0,0,0.3); z-index: 999; transition: all 0.3s ease; } .debug-toggle:hover { transform: scale(1.1); box-shadow: 0 4px 20px rgba(0,0,0,0.4); } .debug-toggle.active { background: var(--ok); } /* Progress indicator for executive requests */ .progress-bar { height: 3px; background: var(--border); border-radius: 2px; overflow: hidden; margin: 8px 0; } .progress-fill { height: 100%; background: var(--primary); transition: width 0.3s ease; border-radius: 2px; } /* Mobile responsive adjustments */ @media (max-width: 768px) { .sidebar { transform: translateX(-100%); } .debug-panel { width: 300px; right: 10px; top: 10px; max-height: 400px; } .debug-toggle { width: 45px; height: 45px; bottom: 15px; right: 15px; } .sidebar.show { transform: translateX(0); } } .chat-input-wrapper { display: flex; align-items: center; gap: 8px; max-width: 1000px; margin: 0 auto; } .chat-input { flex: 1; background: var(--muted); border: 1px solid var(--border); border-radius: 12px; padding: 10px 14px; color: var(--text); font-family: inherit; font-size: 14px; resize: none; min-height: 36px; max-height: 80px; line-height: 1.4; } .chat-input:focus { outline: none; border-color: var(--primary); } .chat-input::placeholder { color: var(--sub); } .input-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } .btn { background: var(--primary); color: white; border: none; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-weight: 500; font-size: 12px; transition: all 0.2s; white-space: nowrap; } .btn:hover { background: #6c7ce0; transform: translateY(-1px); } .btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; } .btn.secondary { background: var(--muted); color: var(--text); border: 1px solid var(--border); } .btn.secondary:hover { background: var(--border); } .btn.ghost { background: transparent; border: 1px solid var(--border); } /* Mobile Toggle */ .mobile-toggle { display: none; background: none; border: none; color: var(--text); cursor: pointer; font-size: 18px; } /* Welcome Screen */ .welcome-screen { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px; text-align: center; } .welcome-title { font-size: 28px; font-weight: 700; margin-bottom: 12px; background: linear-gradient(45deg, var(--primary), #b794f6); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } .welcome-subtitle { font-size: 16px; color: var(--sub); margin-bottom: 32px; max-width: 500px; } .quick-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; max-width: 600px; width: 100%; } .quick-action { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 20px; cursor: pointer; transition: all 0.2s; text-align: center; } .quick-action:hover { border-color: var(--primary); transform: translateY(-2px); } .quick-action-icon { font-size: 24px; margin-bottom: 8px; } .quick-action-title { font-weight: 600; margin-bottom: 4px; } .quick-action-desc { font-size: 12px; color: var(--sub); } /* Modal Styles */ .modal { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); display: none; align-items: center; justify-content: center; z-index: 1000; padding: 20px; } .modal-content { background: var(--panel); border: 1px solid var(--border); border-radius: 16px; width: 100%; max-width: 500px; max-height: 80vh; overflow-y: auto; } .modal-header { padding: 20px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; } .modal-body { padding: 20px; } .form-group { margin-bottom: 16px; } .form-label { display: block; font-size: 13px; font-weight: 600; color: var(--text); margin-bottom: 6px; } .form-input, .form-select { width: 100%; background: var(--muted); color: var(--text); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; font-family: inherit; font-size: 14px; } .form-input:focus, .form-select:focus { outline: none; border-color: var(--primary); } .form-hint { font-size: 12px; color: var(--sub); margin-top: 4px; } /* Status indicator */ .status-indicator { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--sub); margin-left: 8px; } .status-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ok); } .status-dot.error { background: var(--danger); } .status-dot.loading { background: var(--primary); animation: pulse 1.5s infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } /* Responsive */ @media (max-width: 768px) { .sidebar { position: absolute; left: 0; top: 0; height: 100%; z-index: 100; } .mobile-toggle { display: block; } .provider-switcher { display: none; } } /* Code action buttons styling */ .code-actions { display: flex; gap: 8px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); flex-wrap: wrap; } .save-code-btn, .run-code-btn, .copy-code-btn { background: var(--muted); color: var(--text); border: 1px solid var(--border); border-radius: 6px; padding: 6px 12px; font-size: 12px; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; gap: 4px; white-space: nowrap; } .save-code-btn:hover { background: var(--primary); color: var(--primary-ink); border-color: var(--primary); transform: translateY(-1px); } .run-code-btn:hover { background: var(--ok); color: white; border-color: var(--ok); transform: translateY(-1px); } .copy-code-btn:hover { background: var(--border); transform: translateY(-1px); } .save-code-btn:active, .run-code-btn:active, .copy-code-btn:active { transform: translateY(0); } /* Theme toggle button */ .theme-toggle { position: fixed; top: 20px; right: 20px; width: 50px; height: 28px; background: var(--muted); border: 1px solid var(--border); border-radius: 20px; cursor: pointer; display: flex; align-items: center; padding: 2px; z-index: 1000; transition: all 0.3s ease; } .theme-toggle:hover { background: var(--border); } .theme-toggle-slider { width: 24px; height: 24px; background: var(--primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; transition: all 0.3s ease; color: white; } [data-theme="light"] .theme-toggle-slider { transform: translateX(22px); } /* Make header links readable in both themes */ .message .message-content h1 a, .message .message-content h2 a, .message .message-content h3 a { color: var(--text); text-decoration: none; } .message .message-content h1 a:hover, .message .message-content h2 a:hover, .message .message-content h3 a:hover { text-decoration: underline; } /* Smooth transitions for theme switching */ body, .sidebar, .main-content, .chat-messages, .chat-input, .btn, .nav-item, .debug-panel { transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease; } </style> <style> /* Context menu */ .context-menu { position: fixed; background: var(--panel); color: var(--text); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 6px 20px rgba(0,0,0,0.4); display: none; z-index: 1200; min-width: 160px; } .context-menu .item { padding: 8px 12px; cursor: pointer; font-size: 13px; border-bottom: 1px solid var(--border); } .context-menu .item:last-child { border-bottom: none; } .context-menu .item:hover { background: var(--muted); } </style> </head> <body> <style> /* Floating chat panel */ .float-chat-btn { position: fixed; right: 20px; bottom: 20px; z-index: 1100; } .float-chat-panel { position: fixed; right: 20px; bottom: 70px; width: 360px; max-height: 60vh; background: var(--panel); color: var(--text); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.4); display: none; flex-direction: column; overflow: hidden; z-index: 1100; } .float-chat-panel.expanded { left: 20px; right: 20px; top: 70px; bottom: 70px; width: auto; max-height: none; } .float-chat-header { padding: 10px 12px; border-bottom: 1px solid var(--border); display:flex; justify-content: space-between; align-items:center; font-weight: 600; gap: 8px; } .float-chat-header .actions { display:flex; gap:8px; } .float-chat-messages { padding: 10px 12px; overflow-y: auto; flex: 1; font-size: 13px; } .float-chat-input { display:flex; gap:6px; padding: 8px; border-top:1px solid var(--border); } .float-chat-input input { flex:1; } .bubble { margin: 6px 0; padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--bubble); } .bubble.user { background: var(--muted); } </style> <!-- Theme Toggle Button --> <div class="theme-toggle" onclick="toggleTheme()" title="Toggle light/dark mode"> <div class="theme-toggle-slider">šŸŒ™</div> </div> <!-- Sidebar --> <div class="sidebar" id="sidebar"> <div class="sidebar-header"> <div class="logo">šŸ¤– c9ai</div> <div class="status-indicator"> <div class="status-dot" id="statusDot"></div> <span id="statusText">Ready</span> </div> </div> <div class="nav-section"> <div class="nav-section-title">Navigation</div> <div class="nav-item active" data-view="chat"> <span>šŸ’¬</span> Smart Chat </div> <div class="nav-item" data-view="help"> <span>ā“</span> Help </div> <div class="nav-item" data-view="settings"> <span>āš™ļø</span> Settings </div> <div class="nav-item" data-view="system"> <span>šŸ› ļø</span> System </div> <div class="nav-item" data-view="calculators"> <span>🧮</span> Calculators </div> <div class="nav-item" data-view="workflows"> <span>šŸ”€</span> Workflows </div> <div class="nav-item" data-view="terminal"> <span>šŸ’»</span> Terminal </div> </div> <div class="nav-section conversations"> <div class="nav-section-title">Recent Conversations</div> <div class="conversations-list" id="conversationsList"> <!-- Conversations will be populated here --> </div> </div> <div class="nav-section"> <button class="btn secondary" id="newConversationBtn" style="width: 100%;" onclick="startNewConversation()"> āž• New Conversation </button> </div> </div> <!-- Main Content --> <div class="main-content"> <div class="main-header"> <div class="header-left"> <button class="mobile-toggle" onclick="toggleSidebar()">☰</button> <h2 id="viewTitle">AI Chat</h2> </div> <div class="header-right"></div> </div> <!-- Smart Chat View --> <div class="view-content" id="chatView"> <div class="chat-container"> <div class="chat-messages" id="chatMessages"> <div class="welcome-screen" id="welcomeScreen"> <h1 class="welcome-title">Welcome to Smart Chat</h1> <p class="welcome-subtitle">Enhanced execution environment with XML-Lisp transpiler. Create functions, run calculations, and build your personal function library.</p> <div class="quick-actions"> <div class="quick-action" onclick="startNewConversation()" style="border: 2px solid var(--primary); background: var(--primary); color: var(--primary-ink);"> <div class="quick-action-icon">šŸ’¬</div> <div class="quick-action-title">Start Chatting</div> <div class="quick-action-desc">Begin a new conversation</div> </div> <div class="quick-action" onclick="showView('calculators')"> <div class="quick-action-icon">🧮</div> <div class="quick-action-title">Open Calculators</div> <div class="quick-action-desc">Deterministic business calculators</div> </div> <div class="quick-action" onclick="showView('workflows')"> <div class="quick-action-icon">šŸ”€</div> <div class="quick-action-title">Open Workflows</div> <div class="quick-action-desc">Run or build task pipelines</div> </div> <div class="quick-action" onclick="loadQuickAction('Help me write a professional email')"> <div class="quick-action-icon">āœ‰ļø</div> <div class="quick-action-title">Write Email</div> <div class="quick-action-desc">Craft professional messages</div> </div> <div class="quick-action" onclick="loadQuickAction('Create a social media post')"> <div class="quick-action-icon">šŸ“±</div> <div class="quick-action-title">Social Content</div> <div class="quick-action-desc">Generate engaging posts</div> </div> <div class="quick-action" onclick="loadQuickAction('Plan my project or task')"> <div class="quick-action-icon">šŸ“‹</div> <div class="quick-action-title">Project Planning</div> <div class="quick-action-desc">Organize and break down tasks</div> </div> <div class="quick-action" onclick="loadQuickAction('Help me learn something new')"> <div class="quick-action-icon">šŸŽ“</div> <div class="quick-action-title">Learn & Explore</div> <div class="quick-action-desc">Get explanations and tutorials</div> </div> </div> </div> </div> <div class="chat-input-container"> <div class="chat-input-wrapper"> <textarea class="chat-input" id="chatInput" placeholder="Chat naturally or use @calc, @todo, @email, @search for tasks... (Ctrl+Enter to send)" rows="1" ></textarea> <div class="input-actions"> <button class="btn" id="sendBtn" onclick="sendMessage()">Send</button> <button class="btn secondary" onclick="switchToAgent()">Agent</button> <label style="display:flex;gap:4px;align-items:center;font-size:11px;color:var(--sub)"> <input id="toAgent" type="checkbox" /> <span>Tools</span> </label> </div> </div> </div> </div> </div> <!-- Agent View --> <div class="view-content" id="agentView" style="display: none;"> <div style="padding: 20px; max-width: 1000px; margin: 0 auto; min-height: 100%; box-sizing: border-box;"> <h2 style="margin-bottom: 20px;">šŸš€ Agentic Tools</h2> <div style="background: var(--bubble); padding: 20px; border-radius: 12px; margin-bottom: 24px; border: 1px solid var(--border);"> <h3 style="margin-top: 0; color: var(--primary);">šŸŽÆ Task-Focused AI Interface</h3> <p style="margin-bottom: 16px; line-height: 1.6;"> The Agentic Tools interface is designed for complex task execution with local AI models. It provides a dedicated environment for tool-based operations, file management, and automation. </p> <div style="background: var(--muted); padding: 12px; border-radius: 6px; font-size: 13px; color: var(--sub);"> <strong>✨ Key Features:</strong> Local AI execution • Tool-based commands • Task persistence • File operations • API integrations </div> </div> <div class="form-group"> <h3>🌐 Launch Agentic Interface</h3> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 24px;"> <div style="background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 16px;"> <h4 style="margin-top: 0; margin-bottom: 8px;">šŸ› ļø Main Agentic Tools</h4> <p style="font-size: 12px; color: var(--sub); margin-bottom: 12px;"> Dedicated interface for task execution and tool operations </p> <button class="btn primary" onclick="window.open('http://localhost:8787', '_blank')" style="width: 100%;"> Launch Agentic UI (Port 8787) </button> </div> <div style="background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 16px;"> <h4 style="margin-top: 0; margin-bottom: 8px;">⚔ Quick Test Interface</h4> <p style="font-size: 12px; color: var(--sub); margin-bottom: 12px;"> Current embedded agent interface for testing </p> <button class="btn secondary" onclick="showEmbeddedAgent()" style="width: 100%;"> Show Embedded Agent </button> </div> </div> </div> <div class="form-group"> <h3>šŸ”§ Configuration</h3> <div style="background: var(--muted); padding: 15px; border-radius: 8px;"> <p style="margin: 0 0 8px 0; font-size: 13px;"> <strong>Provider Settings:</strong> AI provider selection is managed in the main chat interface. </p> <p style="margin: 0; font-size: 13px; color: var(--sub);"> <strong>Communication:</strong> The agentic tools interface will communicate with this hub via shared task files. </p> </div> </div> <div id="embeddedAgentContainer" style="display: none; margin-top: 24px;"> <h3>Embedded Agent Interface</h3> <div style="border: 1px solid var(--border); border-radius: 8px; height: 500px;"> <iframe id="embeddedAgentFrame" src="" style="width: 100%; height: 100%; border: none; border-radius: 8px;"></iframe> </div> <button class="btn secondary" onclick="hideEmbeddedAgent()" style="margin-top: 8px;"> Hide Embedded Agent </button> </div> </div> </div> <!-- CLI Access View --> <div class="view-content" id="cliView" style="display: none;"> <div style="padding: 20px; max-width: 1000px; margin: 0 auto; min-height: 100%; box-sizing: border-box;"> <h2 style="margin-bottom: 20px;">āŒØļø CLI Access</h2> <div class="form-group"> <h3>Available CLI Commands</h3> <div style="background: var(--muted); padding: 15px; border-radius: 8px; margin-bottom: 20px;"> <div style="font-family: monospace; font-size: 14px; line-height: 1.6;"> <div style="margin-bottom: 8px;"><strong># Interactive Mode</strong></div> <div style="color: var(--primary);">c9ai</div> <div style="margin: 8px 0; opacity: 0.7;"># Launches interactive shell with your current provider settings</div> <div style="margin: 16px 0 8px 0;"><strong># Direct Agent Commands</strong></div> <div style="color: var(--primary);">c9ai agent "list files in current directory"</div> <div style="color: var(--primary);">c9ai-agent "create a Python script for fibonacci"</div> <div style="margin: 8px 0; opacity: 0.7;"># Execute specific tasks with full tool access</div> <div style="margin: 16px 0 8px 0;"><strong># Provider Management</strong></div> <div style="color: var(--primary);">c9ai models list</div> <div style="color: var(--primary);">c9ai switch claude-hybrid</div> <div style="margin: 8px 0; opacity: 0.7;"># List and switch between providers</div> <div style="margin: 16px 0 8px 0;"><strong># Local Stack</strong></div> <div style="color: var(--primary);">c9ai stack</div> <div style="color: var(--primary);">c9ai stack --model ./my-model.gguf --port 8081</div> <div style="margin: 8px 0; opacity: 0.7;"># Start local llama.cpp server + Agent API</div> </div> </div> </div> <div class="form-group"> <h3>Quick CLI Launcher</h3> <p style="margin-bottom: 15px; color: var(--sub);">Launch CLI with your current UI provider settings</p> <div style="display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 20px;"> <button class="btn" onclick="launchCLI('interactive')" style="display: flex; align-items: center; gap: 8px;"> <span>šŸ–„ļø</span> Interactive Mode </button> <button class="btn" onclick="launchCLI('agent')" style="display: flex; align-items: center; gap: 8px;"> <span>šŸ¤–</span> Agent Mode </button> <button class="btn" onclick="launchCLI('models')" style="display: flex; align-items: center; gap: 8px;"> <span>šŸ“‹</span> List Models </button> <button class="btn" onclick="launchCLI('stack')" style="display: flex; align-items: center; gap: 8px;"> <span>šŸš€</span> Start Stack </button> </div> </div> <div class="form-group"> <h3>CLI Installation</h3> <p style="margin-bottom: 15px; color: var(--sub);">Install C9AI CLI globally for system-wide access</p> <div style="background: var(--muted); padding: 15px; border-radius: 8px;"> <div style="font-family: monospace; font-size: 14px; line-height: 1.6;"> <div style="margin-bottom: 8px;"><strong># Install globally</strong></div> <div style="color: var(--primary);">npm install -g .</div> <div style="margin: 8px 0; opacity: 0.7;"># Run from project directory</div> <div style="margin: 16px 0 8px 0;"><strong># Or use scripts</strong></div> <div style="color: var(--primary);">./install.sh</div> <div style="color: var(--primary);">install-windows.bat</div> <div style="margin: 8px 0; opacity: 0.7;"># Platform-specific installers</div> </div> </div> </div> <div class="form-group"> <h3>CLI Sessions</h3> <p style="margin-bottom: 15px; color: var(--sub);">Track and view CLI command history</p> <div id="cliSessions" style="background: var(--muted); padding: 15px; border-radius: 8px; min-height: 200px;"> <div style="text-align: center; color: var(--sub); padding: 40px;"> No CLI sessions tracked yet. CLI sessions will appear here once you start using the CLI. </div> </div> <div style="margin-top: 15px; display: flex; gap: 12px;"> <button class="btn secondary" onclick="refreshCLISessions()">šŸ”„ Refresh Sessions</button> <button class="btn secondary" onclick="clearCLISessions()">šŸ—‘ļø Clear History</button> </div> </div> </div> </div> <!-- Tools View --> <div class="view-content" id="toolsView" style="display: none;"> <div style="padding: 20px; max-width: 1200px; margin: 0 auto; min-height: 100%; box-sizing: border-box;"> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;"> <h2 style="margin: 0;">šŸ”§ Tool Package Manager</h2> <div style="display: flex; gap: 12px;"> <button class="btn secondary" onclick="refreshToolData()">šŸ”„ Refresh</button> <button class="btn secondary" onclick="showBatchInstall()">šŸ“¦ Batch Install</button> </div> </div> <!-- Tool Source Tabs --> <div style="display: flex; gap: 8px; margin-bottom: 20px;"> <button class="btn pill active" data-source="curated" onclick="switchToolSource('curated')">šŸ“š Curated Tools</button> <button class="btn pill" data-source="packages" onclick="switchToolSource('packages')">šŸ“¦ System Packages</button> <button class="btn pill" data-source="installed" onclick="switchToolSource('installed')">āœ… Installed</button> </div> <!-- Tool Statistics --> <div id="toolStats" style="display: flex; gap: 15px; margin-bottom: 25px;"> <div style="background: var(--panel); padding: 15px; border-radius: 8px; flex: 1; border: 1px solid var(--border);"> <div style="font-size: 24px; font-weight: bold; color: var(--primary);" id="totalTools">-</div> <div style="font-size: 12px; color: var(--sub);">Total Tools</div> </div> <div style="background: var(--panel); padding: 15px; border-radius: 8px; flex: 1; border: 1px solid var(--border);"> <div style="font-size: 24px; font-weight: bold; color: var(--ok);" id="installedTools">-</div> <div style="font-size: 12px; color: var(--sub);">Installed</div> </div> <div style="background: var(--panel); padding: 15px; border-radius: 8px; flex: 1; border: 1px solid var(--border);"> <div style="font-size: 24px; font-weight: bold; color: var(--primary);" id="availableTools">-</div> <div style="font-size: 12px; color: var(--sub);">Available</div> </div> <div style="background: var(--panel); padding: 15px; border-radius: 8px; flex: 1; border: 1px solid var(--border);"> <div style="font-size: 24px; font-weight: bold; color: var(--sub);" id="builtinTools">-</div> <div style="font-size: 12px; color: var(--sub);">Built-in</div> </div> </div> <!-- Category Filter --> <div style="margin-bottom: 20px;"> <div style="display: flex; gap: 8px; flex-wrap: wrap;" id="categoryFilters"> <button class="btn pill active" data-category="all">All Tools</button> <button class="btn pill" data-category="available">Available</button> <button class="btn pill" data-category="installed">Installed</button> </div> </div> <!-- Package Search (visible when packages tab is active) --> <div id="packageSearch" style="display: none; margin-bottom: 25px;"> <div style="display: flex; gap: 12px; margin-bottom: 15px;"> <div style="flex: 1; position: relative;"> <input type="text" id="packageSearchInput" placeholder="Search for packages (e.g., pandoc, ffmpeg, python packages...)" style="width: 100%; padding: 12px 16px; border: 1px solid var(--border); border-radius: 6px; background: var(--panel); color: var(--text);" onkeydown="if(event.key === 'Enter') searchPackages()" /> </div> <button class="btn primary" onclick="searchPackages()">šŸ” Search</button> </div> <!-- Package Manager Status --> <div id="packageManagerStatus" style="display: flex; gap: 10px; margin-bottom: 15px; flex-wrap: wrap;"> Loading package managers... </div> <div id="searchResults" style="display: none;"> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;"> <h3 style="margin: 0;">Search Results</h3> <div id="searchResultsCount" style="color: var(--sub); font-size: 14px;"></div> </div> <div id="packageResults" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); gap: 15px;"> <!-- Search results will be populated here --> </div> </div> </div> <!-- Tool Grid --> <div id="toolGrid" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); gap: 20px;"> <!-- Tools will be populated here --> <div style="grid-column: 1 / -1; text-align: center; padding: 40px; color: var(--sub);"> Loading tools... </div> </div> </div> </div> <!-- Settings View --> <div class="view-content" id="settingsView" style="display: none;"> <div style="padding: 20px; max-width: 600px; margin: 0 auto; min-height: 100%; box-sizing: border-box;"> <h2 style="margin-bottom: 20px;">Settings</h2> <div class="form-group"> <label class="form-label">Default Provider</label> <select class="form-select" id="settingsProvider"> <optgroup label="šŸ  Local Models"> <option value="llamacpp">Llama.cpp (Local)</option> <option value="ollama">Ollama (Local)</option> </optgroup> <optgroup label="ā˜ļø Cloud Models (No Tools)"> <option value="claude">Claude AI</option> <option value="gemini">Gemini AI</option> <option value="openai">OpenAI GPT</option> <option value="deepseek">DeepSeek AI</option> </optgroup> <optgroup label="šŸ”€ Hybrid (Cloud + Local Tools)"> <option value="claude-hybrid">Claude AI + Local Tools</option> <option value="gemini-hybrid">Gemini AI + Local Tools</option> <option value="openai-hybrid">OpenAI GPT + Local Tools</option> <option value="deepseek-hybrid">DeepSeek AI + Local Tools</option> </optgroup> </select> <div class="form-hint">Choose your preferred AI model provider</div> </div> <div class="form-group"> <label class="form-label">Mode</label> <select class="form-select" id="settingsMode"> <option value="local">Local Only</option> <option value="hybrid" selected>Hybrid (default)</option> <option value="cloud">Cloud Only</option> </select> <div class="form-hint">Route tasks between local llama.cpp and cloud</div> </div> <div class="form-group"> <label class="form-label">Privacy Profile</label> <select class="form-select" id="settingsPrivacy"> <option value="strict_local">Strict Local (never use cloud)</option> <option value="ask_before_cloud" selected>Ask Before Cloud</option> <option value="cloud_preferred">Cloud Preferred</option> </select> <div class="form-hint">Controls cloud escalation behavior</div> </div> <div class="form-group"> <label class="form-label">Coding Provider</label> <select class="form-select" id="settingsCodingProvider"> <option value="llamacpp">Local (llama.cpp)</option> <option value="claude">Claude</option> <option value="openai">OpenAI</option> <option value="gemini">Gemini</option> <option value="deepseek">DeepSeek</option> </select> <div class="form-hint">Preferred model for code tasks</div> </div> <div class="form-group"> <label class="form-label">Confirmation Threshold</label> <input type="number" class="form-input" id="settingsThreshold" min="0" max="1" step="0.1" value="0.6"> <div class="form-hint">Threshold for automatic task execution (0-1)</div> </div> <div class="form-group"> <label class="form-label">Allowed Tools</label> <input type="text" class="form-input" id="settingsTools" placeholder="shell.run,script.run,fs.read,fs.write"> <div class="form-hint">Comma-separated list of allowed tools</div> </div> <div class="form-group"> <label class="form-label">API Keys</label> <div style="margin-bottom: 15px;"> <label class="form-label" style="font-size: 14px; margin-bottom: 5px;">Claude (Anthropic)</label> <input type="password" class="form-input" id="settingsClaudeApi" placeholder="ANTHROPIC_API_KEY"> <div class="form-hint">Required for Claude AI provider fallback</div> </div> <div style="margin-bottom: 15px;"> <label class="form-label" style="font-size: 14px; margin-bottom: 5px;">Gemini (Google)</label> <input type="password" class="form-input" id="settingsGeminiApi" placeholder="GEMINI_API_KEY"> <div class="form-hint">For Google's Gemini AI models</div> </div> <div style="margin-bottom: 15px;"> <label class="form-label" style="font-size: 14px; margin-bottom: 5px;">OpenAI</label> <input type="password" class="form-input" id="settingsOpenAIApi" placeholder="OPENAI_API_KEY"> <div class="form-hint">For GPT models</div> </div> <div style="margin-bottom: 15px;"> <label class="form-label" style="font-size: 14px; margin-bottom: 5px;">DeepSeek</label> <input type="password" class="form-input" id="settingsDeepSeekApi" placeholder="DEEPSEEK_API_KEY"> <div class="form-hint">Cost-effective AI alternative</div> </div> <div style="margin-bottom: 15px;"> <label class="form-label" style="font-size: 14px; margin-bottom: 5px;">KnoblyCream API</label> <input type="password" class="form-input" id="settingsCreamApi" placeholder="CREAM_API_KEY"> <div class="form-hint">For RSS feeds, posts, and email functionality</div> </div> <div style="margin-bottom: 15px;"> <label class="form-label" style="font-size: 14px; margin-bottom: 5px;">YouTube API</label> <input type="password" class="form-input" id="settingsYouTubeApi" placeholder="YOUTUBE_API_KEY"> <div class="form-hint">For YouTube video search and trending videos</div> </div> <div style="margin-bottom: 15px;"> <label class="form-label" style="font-size: 14px; margin-bottom: 5px;">SerpAPI (Web Search)</label> <input type="password" class="form-input" id="settingsSerpApi" placeholder="SERPAPI_KEY"> <div class="form-hint">For web search functionality</div> </div> </div> <button class="btn" id="saveSettingsBtn" onclick="saveSettings()">Save Settings</button> <div style="height: 40px;"></div> <!-- Spacer for scroll --> </div> </div> <!-- Workflows View --> <div class="view-content" id="workflowsView" style="display:none;"> <div style="padding: 20px; max-width: 1100px; margin: 0 auto;"> <h2 style="margin-bottom:16px;">Workflow Builder</h2> <div style="display:grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap:16px;"> <!-- Analyze Document --> <div style="border:1px solid var(--border); border-radius:10px; padding:14px; background:var(--panel);"> <h3 style="margin:0 0 10px 0;">Analyze Document/Spreadsheet</h3> <div class="form-group"><label class="form-label">Path</label><input id="wfAnalyzePath" class="form-input" type="text" placeholder="/path/to/file.csv"/></div> <button class="btn" onclick="runWorkflowAnalyze(document.getElementById('wfAnalyzePath').value)">Run</button> <div id="workflowAnalyzeResult" style="margin-top:10px; font-size:13px; max-height:220px; overflow:auto;"></div> </div> <!-- Build Document --> <div style="border:1px solid var(--border); border-radius:10px; padding:14px; background:var(--panel);"> <h3 style="margin:0 0 10px 0;">Build New Document</h3> <div class="form-group"><label class="form-label">Title</label><input id="wfBuildTitle" class="form-input" type="text" placeholder="Quarterly Summary"/></div> <div class="form-group"><label class="form-label">Sections (bullets)</label><textarea id="wfBuildSections" class="form-input" style="min-height:100px;" placeholder="• Revenue trends\n• Key risks\n• Next steps"></textarea></div> <div class="form-group"><label class="form-label">Format</label><select id="wfBuildFormat" class="form-select"><option>markdown</option><option>latex</option></select></div> <button class="btn" onclick="runWorkflowBuild(document.getElementById('wfBuildTitle').value, document.getElementById('wfBuildSections').value, document.getElementById('w