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
HTML
<!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