agent-ui / frontend /index.html
lvwerra's picture
lvwerra HF Staff
Fix welcome notice spacing and style Important in theme color
72028e1
Raw
History Blame Contribute Delete
35.5 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AgentUI</title>
<link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="apple-touch-icon" href="apple-touch-icon.png">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<link rel="stylesheet" href="style.css?v=112">
</head>
<body>
<div class="app-container">
<!-- Tab Bar -->
<div class="tab-bar">
<div class="tab active" data-tab-id="0">
<span class="tab-title">MAIN</span>
</div>
<div id="dynamicTabs"></div>
<div class="new-tab-wrapper">
<button class="new-tab-btn" id="newTabBtn">+</button>
<div class="new-tab-menu" id="newTabMenu">
<!-- Generated dynamically from AGENT_REGISTRY -->
</div>
</div>
<div class="tab-bar-spacer"></div>
<button class="sessions-btn" id="sessionsBtn">sessions</button>
<button class="files-btn" id="filesBtn">files</button>
<button class="debug-btn" id="debugBtn">debug</button>
<button class="settings-btn" id="settingsBtn">settings</button>
</div>
<!-- Tab Content Area -->
<div class="content-area">
<!-- Left Sidebar - Timeline Overview -->
<div class="agents-sidebar" id="agentsSidebar">
<div id="userIndicator" class="user-indicator-block" style="display:none">
<span class="workspace-label">USER</span>
<span class="user-indicator-name" id="userIndicatorName"></span>
</div>
<div class="sidebar-content" id="sidebarAgents">
<!-- Timeline widgets will be rendered here -->
</div>
<div class="sidebar-legend">
<span><span class="legend-square"></span> user</span>
<span><span class="legend-circle"></span> assistant</span>
<span><span class="legend-box"></span> agent/tool</span>
</div>
<div class="sidebar-controls">
<span class="sidebar-controls-label">Timeline view:</span>
<label class="sidebar-checkbox"><input type="checkbox" id="compactViewCheckbox"> compact</label>
</div>
<div class="sidebar-controls">
<span class="sidebar-controls-label">Chat collapse:</span>
<label class="sidebar-checkbox"><input type="checkbox" id="collapseAgentsCheckbox"> agents</label>
<label class="sidebar-checkbox"><input type="checkbox" id="collapseToolsCheckbox"> tools</label>
</div>
<div class="sidebar-resize-handle" id="sidebarResizeHandle"></div>
</div>
<!-- Main Content -->
<div class="main-content">
<!-- Task Center Tab -->
<div class="tab-content active" data-content-id="0">
<div class="agent-interface">
<div class="agent-header">
<div>
<div class="agent-type">TASK CENTER</div>
<h2>Task Center</h2>
</div>
<div class="header-actions" id="launcherButtons">
<!-- Launcher buttons generated dynamically from AGENT_REGISTRY -->
<button class="debug-btn" id="debugBtn">DEBUG</button>
</div>
</div>
<div class="agent-body">
<div class="chat-container" id="messages-command">
<div class="welcome-message" id="welcomeMessage">
<p>Welcome to AgentUI — an AI interface with specialized agents.</p>
<div class="session-selector" id="sessionSelector">
<div class="session-selector-form">
<div class="session-new">
<label>New session:</label>
<div class="session-new-input">
<div class="session-input-wrapper">
<input type="text" id="newSessionName" placeholder="Session name..." />
<button type="button" class="session-regenerate-btn" id="regenerateNameBtn" title="Generate new name"></button>
</div>
<button id="createSessionBtn">START</button>
</div>
</div>
<div class="session-existing">
<label>Or continue:</label>
<select id="existingSessionSelect">
<option value="">-- Select session --</option>
</select>
</div>
</div>
</div>
<div class="welcome-explanation">
<p>The assistant can automatically open specialized agents for different tasks:</p>
<ul>
<li><strong style="color: var(--theme-accent)">BASE</strong> — Basic tasks with search</li>
<li><strong style="color: var(--theme-accent)">CODE</strong> — Programming and data analysis</li>
<li><strong style="color: var(--theme-accent)">RESEARCH</strong> — Deep research and information gathering</li>
<li><strong style="color: var(--theme-accent)">IMAGE</strong> — Image generation and editing</li>
<li><strong style="color: var(--theme-accent)">COMPUTER</strong> <em>(coming soon)</em> — Computer control and automation</li>
</ul>
<div class="welcome-diagram">
<div class="tl-widget compact">
<div class="workspace-block">
<div class="workspace-label">Agent</div>
<div class="workspace-name">Main agent</div>
</div>
<div class="tl">
<!-- User query -->
<div class="tl-row turn user"><div class="tl-dot"></div><span class="tl-label">User query</span></div>
<!-- Thinking -->
<div class="tl-row turn"><div class="tl-dot"></div><span class="tl-label">Routing to sub-agents...</span></div>
<!-- Research sub-agent -->
<div class="tl-row has-agent has-nested">
<div class="tl-dot"></div>
<div class="agent-box">
<div class="agent-header"><div class="collapse-toggle"></div><span>Research</span></div>
<div class="agent-body">
<span class="agent-body-text">Sub-agent</span>
<div class="agent-status"><span>12 turns</span><div class="agent-done"></div></div>
</div>
</div>
</div>
<div class="tl-nested complete">
<div class="tl">
<div class="tl-row turn"><div class="tl-dot"></div><div class="tl-tool"><span class="tl-tool-tag">search</span><span class="tl-tool-text">"topic overview"</span></div></div>
<div class="tl-row turn"><div class="tl-dot"></div><div class="tl-tool"><span class="tl-tool-tag">read</span><span class="tl-tool-text">4 sources</span></div></div>
<div class="tl-row turn"><div class="tl-dot"></div><span class="tl-label">Synthesizing...</span></div>
<div class="tl-row turn"><div class="tl-dot"></div><div class="tl-tool"><span class="tl-tool-tag">result</span></div></div>
</div>
</div>
<div class="tl-row tl-return"><div class="tl-dot"></div><div class="tl-return-connector"></div></div>
<!-- Code sub-agent -->
<div class="tl-row has-agent has-nested">
<div class="tl-dot"></div>
<div class="agent-box">
<div class="agent-header"><div class="collapse-toggle"></div><span>Code</span></div>
<div class="agent-body">
<span class="agent-body-text">Sub-agent</span>
<div class="agent-status"><span>4 turns</span><div class="agent-done"></div></div>
</div>
</div>
</div>
<div class="tl-nested complete">
<div class="tl">
<div class="tl-row turn"><div class="tl-dot"></div><div class="tl-tool"><span class="tl-tool-tag">code</span><span class="tl-tool-text">import numpy as np</span></div></div>
<div class="tl-row turn"><div class="tl-dot"></div><div class="tl-tool"><span class="tl-tool-tag">code</span><span class="tl-tool-text">plt.show()</span></div></div>
<div class="tl-row turn"><div class="tl-dot"></div><div class="tl-tool"><span class="tl-tool-tag">result</span><span class="tl-tool-text">2 figures</span></div></div>
</div>
</div>
<div class="tl-row tl-return"><div class="tl-dot"></div><div class="tl-return-connector"></div></div>
<!-- Image sub-agent -->
<div class="tl-row has-agent has-nested">
<div class="tl-dot"></div>
<div class="agent-box">
<div class="agent-header"><div class="collapse-toggle"></div><span>Image</span></div>
<div class="agent-body">
<span class="agent-body-text">Sub-agent</span>
<div class="agent-status"><span>2 turns</span><div class="agent-done"></div></div>
</div>
</div>
</div>
<div class="tl-nested complete">
<div class="tl">
<div class="tl-row turn"><div class="tl-dot"></div><span class="tl-label">Generating image...</span></div>
<div class="tl-row turn"><div class="tl-dot"></div><div class="tl-tool"><span class="tl-tool-tag">result</span><span class="tl-tool-text">1 image</span></div></div>
</div>
</div>
<div class="tl-row tl-return"><div class="tl-dot"></div><div class="tl-return-connector"></div></div>
<!-- Assistant summarizes -->
<div class="tl-row turn"><div class="tl-dot"></div><span class="tl-label">Summarize results</span></div>
</div>
</div>
</div>
<p>When an agent is opened, you'll see a widget you can click to jump to it. A pulsing dot on the tab indicates active generation.</p>
</div>
</div>
</div>
</div>
<div class="input-area" id="commandInputArea" style="display: none;">
<div class="input-container">
<textarea placeholder="Enter message..." id="input-command" rows="1"></textarea>
<button id="sendCommand">SEND</button>
</div>
</div>
</div>
</div>
</div><!-- /.main-content -->
</div>
</div>
<!-- Settings Panel -->
<div class="settings-panel" id="settingsPanel">
<div class="settings-panel-header">
<h3>SETTINGS</h3>
<span class="settings-path" id="settingsPath"></span>
<button class="settings-panel-close" id="settingsPanelClose">×</button>
</div>
<div class="settings-panel-body" id="settingsPanelBody">
<div class="settings-body">
<!-- 1. Agent Models -->
<div class="settings-group">
<div class="settings-group-header">
<div class="widget-collapse-toggle"></div>
<span class="settings-group-title">Agent Models</span>
</div>
<div class="settings-group-body">
<div class="settings-section">
<div class="agent-models-grid" id="agentModelsGrid">
<!-- Generated dynamically from AGENT_REGISTRY -->
</div>
</div>
</div>
</div>
<!-- 2. Models & Providers -->
<div class="settings-group collapsed">
<div class="settings-group-header">
<div class="widget-collapse-toggle collapsed"></div>
<span class="settings-group-title">Models & Providers</span>
</div>
<div class="settings-group-body">
<div class="settings-section">
<label class="settings-label">
<span class="label-text">PROVIDERS</span>
<span class="label-description">API endpoints for LLM services</span>
</label>
<div id="providers-list" class="settings-list"></div>
<button type="button" class="settings-add-btn" onclick="showProviderDialog()">+ Add Provider</button>
</div>
<div class="settings-section">
<label class="settings-label">
<span class="label-text">MODELS</span>
<span class="label-description">Models available from your providers</span>
</label>
<div id="models-list" class="settings-list"></div>
<button type="button" class="settings-add-btn" onclick="showModelDialog()">+ Add Model</button>
</div>
</div>
</div>
<!-- 3. API Keys -->
<div class="settings-group collapsed">
<div class="settings-group-header">
<div class="widget-collapse-toggle collapsed"></div>
<span class="settings-group-title">API Keys</span>
</div>
<div class="settings-group-body">
<div class="settings-section">
<label class="settings-label">
<span class="label-text">E2B API KEY</span>
<span class="label-description">Required for code execution in CODE agents</span>
</label>
<input type="password" id="setting-e2b-key" class="settings-input" placeholder="Leave empty if not using code execution">
</div>
<div class="settings-section">
<label class="settings-label">
<span class="label-text">SERPER API KEY</span>
<span class="label-description">Required for web search in RESEARCH agents</span>
</label>
<input type="password" id="setting-serper-key" class="settings-input" placeholder="Leave empty if not using research">
</div>
<div class="settings-section">
<label class="settings-label">
<span class="label-text">HUGGINGFACE TOKEN</span>
<span class="label-description">Required for image generation in IMAGE agents</span>
</label>
<input type="password" id="setting-hf-token" class="settings-input" placeholder="Leave empty to use provider token">
</div>
</div>
</div>
<!-- 4. Agent Settings -->
<div class="settings-group collapsed">
<div class="settings-group-header">
<div class="widget-collapse-toggle collapsed"></div>
<span class="settings-group-title">Agent Settings</span>
</div>
<div class="settings-group-body">
<div class="settings-section">
<label class="settings-label">
<span class="label-text">IMAGE GENERATION MODEL</span>
<span class="label-description">Model for text-to-image generation</span>
</label>
<select id="setting-image-gen-model" class="settings-select"></select>
</div>
<div class="settings-section">
<label class="settings-label">
<span class="label-text">IMAGE EDIT MODEL</span>
<span class="label-description">Model for image-to-image editing</span>
</label>
<select id="setting-image-edit-model" class="settings-select"></select>
</div>
<div class="settings-section">
<label class="settings-label">
<span class="label-text">RESEARCH SUB-AGENT MODEL</span>
<span class="label-description">Smaller/faster model for analyzing web pages during research</span>
</label>
<select id="setting-research-sub-agent-model" class="settings-select"></select>
</div>
<div class="settings-section">
<label class="settings-label">
<span class="label-text">RESEARCH PARALLEL WORKERS</span>
<span class="label-description">Number of web pages to analyze in parallel (default: 8)</span>
</label>
<input type="number" id="setting-research-parallel-workers" class="settings-input" placeholder="8" min="1" max="20">
</div>
<div class="settings-section">
<label class="settings-label">
<span class="label-text">RESEARCH MAX WEBSITES</span>
<span class="label-description">Max websites to analyze per session (default: 50)</span>
</label>
<input type="number" id="setting-research-max-websites" class="settings-input" placeholder="50" min="10" max="200">
</div>
</div>
</div>
<!-- 5. Theme -->
<div class="settings-group collapsed">
<div class="settings-group-header">
<div class="widget-collapse-toggle collapsed"></div>
<span class="settings-group-title">Theme</span>
</div>
<div class="settings-group-body">
<div class="settings-section">
<div class="theme-color-picker" id="theme-color-picker">
<div class="theme-option" data-theme="forest">
<div class="theme-preview" style="border-color: #1b5e20; background: #e8f5e9;"></div>
<span class="theme-name">Forest</span>
</div>
<div class="theme-option" data-theme="sapphire">
<div class="theme-preview" style="border-color: #0d47a1; background: #e3f2fd;"></div>
<span class="theme-name">Sapphire</span>
</div>
<div class="theme-option" data-theme="ocean">
<div class="theme-preview" style="border-color: #00796b; background: #e0f2f1;"></div>
<span class="theme-name">Ocean</span>
</div>
<div class="theme-option" data-theme="midnight">
<div class="theme-preview" style="border-color: #283593; background: #e8eaf6;"></div>
<span class="theme-name">Midnight</span>
</div>
<div class="theme-option" data-theme="steel">
<div class="theme-preview" style="border-color: #455a64; background: #eceff1;"></div>
<span class="theme-name">Steel</span>
</div>
<div class="theme-option" data-theme="depths">
<div class="theme-preview" style="border-color: #01579b; background: #e3f2fd;"></div>
<span class="theme-name">Depths</span>
</div>
<div class="theme-option" data-theme="ember">
<div class="theme-preview" style="border-color: #b71c1c; background: #fbe9e7;"></div>
<span class="theme-name">Ember</span>
</div>
<div class="theme-option" data-theme="noir">
<div class="theme-preview" style="border-color: #888888; background: #111111;"></div>
<span class="theme-name">Noir</span>
</div>
<div class="theme-option" data-theme="eclipse">
<div class="theme-preview" style="border-color: #5c9eff; background: #0b1118;"></div>
<span class="theme-name">Eclipse</span>
</div>
<div class="theme-option" data-theme="terminal">
<div class="theme-preview" style="border-color: #00cc00; background: #0a0a0a;"></div>
<span class="theme-name">Terminal</span>
</div>
</div>
<input type="hidden" id="setting-theme-color" value="forest">
</div>
</div>
</div>
<div class="settings-actions">
<button class="settings-save-btn" id="saveSettingsBtn">SAVE</button>
<button class="settings-cancel-btn" id="cancelSettingsBtn">CANCEL</button>
</div>
<div class="settings-status" id="settingsStatus"></div>
</div>
</div>
</div>
<!-- Debug Panel -->
<div class="debug-panel" id="debugPanel">
<div class="debug-header">
<h3>DEBUG: Message History</h3>
<button class="debug-close" id="debugClose">×</button>
</div>
<div class="debug-body">
<pre class="debug-content" id="debugContent">No message history available yet.</pre>
</div>
</div>
<!-- Files Panel -->
<div class="files-panel" id="filesPanel">
<div class="files-panel-header">
<h3>FILES</h3>
<div class="files-panel-controls">
<label class="files-show-hidden">
<input type="checkbox" id="showHiddenFiles">
<span>Hidden</span>
</label>
<button class="files-upload-btn" id="filesUpload" title="Upload file">+</button>
<button class="files-refresh-btn" id="filesRefresh" title="Refresh"></button>
</div>
<button class="files-panel-close" id="filesPanelClose">×</button>
</div>
<div class="files-panel-body" id="fileTree">
<div class="files-loading">Loading...</div>
</div>
<div class="files-panel-legend">
<span>Click: insert path</span>
<span>Double-click: expand</span>
<span>Drag: to input</span>
</div>
</div>
<!-- Sessions Panel -->
<div class="sessions-panel" id="sessionsPanel">
<div class="sessions-panel-header">
<h3>SESSIONS</h3>
<button class="sessions-panel-close" id="sessionsPanelClose">×</button>
</div>
<div class="sessions-panel-body">
<div class="sessions-current">
<label>Current session:</label>
<div class="sessions-current-name">
<input type="text" id="currentSessionRename" placeholder="Session name" />
<button id="renameSessionBtn" title="Rename"></button>
</div>
</div>
<div class="sessions-divider"></div>
<div class="sessions-new">
<label>New session:</label>
<div class="sessions-new-input">
<div class="session-input-wrapper">
<input type="text" id="panelNewSessionName" placeholder="Name..." />
<button type="button" class="session-regenerate-btn" id="panelRegenerateNameBtn" title="Generate new name"></button>
</div>
<button id="panelCreateSessionBtn">CREATE</button>
</div>
</div>
<div class="sessions-divider"></div>
<div class="sessions-list-section">
<label>Switch to:</label>
<div class="sessions-list" id="sessionsList">
<div class="sessions-loading">Loading...</div>
</div>
</div>
</div>
</div>
<!-- Provider Dialog -->
<div class="settings-dialog-overlay" id="provider-dialog">
<div class="settings-dialog">
<div class="settings-dialog-header">
<h3 id="provider-dialog-title">Add Provider</h3>
<button class="settings-dialog-close" onclick="hideProviderDialog()">×</button>
</div>
<div class="settings-dialog-body">
<div class="dialog-field">
<label class="dialog-label">NAME</label>
<input type="text" id="provider-name" class="settings-input" placeholder="e.g., OpenAI, Local vLLM">
</div>
<div class="dialog-field">
<label class="dialog-label">ENDPOINT</label>
<input type="text" id="provider-endpoint" class="settings-input" placeholder="e.g., https://api.openai.com/v1">
</div>
<div class="dialog-field">
<label class="dialog-label">API TOKEN</label>
<input type="password" id="provider-token" class="settings-input" placeholder="sk-...">
</div>
</div>
<div class="settings-dialog-actions">
<button class="settings-save-btn" onclick="saveProviderFromDialog()">SAVE</button>
<button class="settings-cancel-btn" onclick="hideProviderDialog()">CANCEL</button>
</div>
</div>
</div>
<!-- Model Dialog -->
<div class="settings-dialog-overlay" id="model-dialog">
<div class="settings-dialog">
<div class="settings-dialog-header">
<h3 id="model-dialog-title">Add Model</h3>
<button class="settings-dialog-close" onclick="hideModelDialog()">×</button>
</div>
<div class="settings-dialog-body">
<div class="dialog-field">
<label class="dialog-label">DISPLAY NAME</label>
<input type="text" id="model-name" class="settings-input" placeholder="e.g., GPT-4o, Claude 3.5">
</div>
<div class="dialog-field">
<label class="dialog-label">PROVIDER</label>
<select id="model-provider" class="settings-select">
<option value="">-- Select Provider --</option>
</select>
</div>
<div class="dialog-field">
<label class="dialog-label">MODEL ID</label>
<input type="text" id="model-model-id" class="settings-input" placeholder="e.g., gpt-4o, claude-3-5-sonnet-20241022">
<span class="dialog-hint">The exact model identifier used in API calls</span>
</div>
<div class="dialog-field">
<label class="dialog-label">EXTRA PARAMETERS</label>
<textarea id="model-extra-params" class="settings-textarea" placeholder='{"enable_thinking": false}' rows="3"></textarea>
<span class="dialog-hint">Optional JSON object with extra parameters for API calls (e.g., enable_thinking, temperature)</span>
</div>
<div class="dialog-field">
<label class="dialog-checkbox-label"><input type="checkbox" id="model-multimodal"> Supports vision / image input</label>
</div>
</div>
<div class="settings-dialog-actions">
<button class="settings-save-btn" onclick="saveModelFromDialog()">SAVE</button>
<button class="settings-cancel-btn" onclick="hideModelDialog()">CANCEL</button>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-python.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<!-- Username overlay for multi-user mode -->
<div id="usernameOverlay" class="username-overlay" style="display:none">
<div class="username-dialog">
<h2>Welcome to AgentUI</h2>
<p>Enter your name to get started</p>
<input type="search" id="usernameInput" name="display_nickname" placeholder="Your name" maxlength="30" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" data-1p-ignore data-lpignore="true" data-bwignore data-form-type="other" role="presentation">
<div id="usernameWarning" class="username-warning" style="display:none"></div>
<button id="usernameSubmit">Start</button>
<p class="username-notice"><strong>Important:</strong> This is a shared space — other users may access your data. Do not add API keys. Session data is stored for persistence in a private bucket. For private use, <a href="https://github.com/huggingface/agent-ui" target="_blank">clone the repo</a> and run locally.</p>
</div>
</div>
<script src="utils.js?v=1"></script>
<script src="research-ui.js?v=23"></script>
<script src="timeline.js?v=1"></script>
<script src="sessions.js?v=1"></script>
<script src="streaming.js?v=1"></script>
<script src="tabs.js?v=1"></script>
<script src="workspace.js?v=1"></script>
<script src="settings.js?v=1"></script>
<script src="app.js?v=1"></script>
</body>
</html>