From f766e6ee476fde826900c45a1ddc3e85ad7d8705 Mon Sep 17 00:00:00 2001 From: v0 Date: Sat, 16 May 2026 09:53:41 +0000 Subject: [PATCH 01/13] feat: build VoltAgent Dashboard system Create dashboard package with TopBar, Sidebar, and 10 pages Co-authored-by: Abkdarrk <122768967+Abdullakala@users.noreply.github.com> --- packages/dashboard/index.html | 13 + packages/dashboard/package.json | 29 + packages/dashboard/postcss.config.js | 6 + packages/dashboard/src/App.tsx | 6 + .../dashboard/src/components/Shell/Shell.tsx | 52 ++ .../src/components/Shell/Sidebar.tsx | 128 ++++ .../dashboard/src/components/Shell/TopBar.tsx | 66 ++ packages/dashboard/src/index.css | 22 + packages/dashboard/src/index.tsx | 14 + packages/dashboard/src/pages/Agents.tsx | 151 ++++ packages/dashboard/src/pages/Analytics.tsx | 276 ++++++++ packages/dashboard/src/pages/Logs.tsx | 134 ++++ .../dashboard/src/pages/Observability.tsx | 405 +++++++++++ packages/dashboard/src/pages/OtherPages.tsx | 65 ++ packages/dashboard/src/pages/Settings.tsx | 107 +++ packages/dashboard/src/pages/Traces.tsx | 109 +++ packages/dashboard/tailwind.config.js | 11 + packages/dashboard/tsconfig.json | 23 + packages/dashboard/vite.config.ts | 10 + pnpm-lock.yaml | 657 +++++++++++------- 20 files changed, 2032 insertions(+), 252 deletions(-) create mode 100644 packages/dashboard/index.html create mode 100644 packages/dashboard/package.json create mode 100644 packages/dashboard/postcss.config.js create mode 100644 packages/dashboard/src/App.tsx create mode 100644 packages/dashboard/src/components/Shell/Shell.tsx create mode 100644 packages/dashboard/src/components/Shell/Sidebar.tsx create mode 100644 packages/dashboard/src/components/Shell/TopBar.tsx create mode 100644 packages/dashboard/src/index.css create mode 100644 packages/dashboard/src/index.tsx create mode 100644 packages/dashboard/src/pages/Agents.tsx create mode 100644 packages/dashboard/src/pages/Analytics.tsx create mode 100644 packages/dashboard/src/pages/Logs.tsx create mode 100644 packages/dashboard/src/pages/Observability.tsx create mode 100644 packages/dashboard/src/pages/OtherPages.tsx create mode 100644 packages/dashboard/src/pages/Settings.tsx create mode 100644 packages/dashboard/src/pages/Traces.tsx create mode 100644 packages/dashboard/tailwind.config.js create mode 100644 packages/dashboard/tsconfig.json create mode 100644 packages/dashboard/vite.config.ts diff --git a/packages/dashboard/index.html b/packages/dashboard/index.html new file mode 100644 index 000000000..cfcf02db0 --- /dev/null +++ b/packages/dashboard/index.html @@ -0,0 +1,13 @@ + + + + + + + VoltAgent - AI Agent Observability Platform + + +
+ + + diff --git a/packages/dashboard/package.json b/packages/dashboard/package.json new file mode 100644 index 000000000..b70f2ef1f --- /dev/null +++ b/packages/dashboard/package.json @@ -0,0 +1,29 @@ +{ + "name": "@voltagent/dashboard", + "version": "0.1.0", + "description": "VoltAgent Dashboard - AI Agent Observability Platform", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "framer-motion": "^11.15.0", + "lucide-react": "^0.468.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "recharts": "^2.15.0" + }, + "devDependencies": { + "@types/react": "^18.3.16", + "@types/react-dom": "^18.3.5", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.17", + "typescript": "^5.8.2", + "vite": "^7.2.7" + } +} diff --git a/packages/dashboard/postcss.config.js b/packages/dashboard/postcss.config.js new file mode 100644 index 000000000..2e7af2b7f --- /dev/null +++ b/packages/dashboard/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/packages/dashboard/src/App.tsx b/packages/dashboard/src/App.tsx new file mode 100644 index 000000000..b8dd04fb9 --- /dev/null +++ b/packages/dashboard/src/App.tsx @@ -0,0 +1,6 @@ +import React from 'react' +import { Shell } from './components/Shell/Shell' + +export function App() { + return +} diff --git a/packages/dashboard/src/components/Shell/Shell.tsx b/packages/dashboard/src/components/Shell/Shell.tsx new file mode 100644 index 000000000..c822b7eab --- /dev/null +++ b/packages/dashboard/src/components/Shell/Shell.tsx @@ -0,0 +1,52 @@ +import React, { useState } from 'react' +import { TopBar } from './TopBar' +import { Sidebar, ViewType } from './Sidebar' +// Import Pages +import { Observability } from '../../pages/Observability' +import { Agents } from '../../pages/Agents' +import { Analytics } from '../../pages/Analytics' +import { Traces } from '../../pages/Traces' +import { Logs } from '../../pages/Logs' +import { Settings } from '../../pages/Settings' +import { Memory, Workflows, Tools, Prompts } from '../../pages/OtherPages' + +export function Shell() { + const [activeView, setActiveView] = useState('observability') + + const renderView = () => { + switch (activeView) { + case 'observability': + return + case 'agents': + return + case 'analytics': + return + case 'traces': + return + case 'logs': + return + case 'settings': + return + case 'memory': + return + case 'workflows': + return + case 'tools': + return + case 'prompts': + return + default: + return + } + } + + return ( +
+ +
+ +
{renderView()}
+
+
+ ) +} diff --git a/packages/dashboard/src/components/Shell/Sidebar.tsx b/packages/dashboard/src/components/Shell/Sidebar.tsx new file mode 100644 index 000000000..c0814b985 --- /dev/null +++ b/packages/dashboard/src/components/Shell/Sidebar.tsx @@ -0,0 +1,128 @@ +import React from 'react' +import { + Activity, + Bot, + GitBranch, + Database, + Workflow, + Wrench, + FileText, + Terminal, + BarChart3, + Settings, +} from 'lucide-react' + +export type ViewType = + | 'observability' + | 'agents' + | 'traces' + | 'memory' + | 'workflows' + | 'tools' + | 'prompts' + | 'logs' + | 'analytics' + | 'settings' + +interface SidebarProps { + activeView: ViewType + onViewChange: (view: ViewType) => void +} + +const navItems = [ + { + id: 'observability', + icon: Activity, + label: 'Observability', + }, + { + id: 'agents', + icon: Bot, + label: 'Agents', + }, + { + id: 'traces', + icon: GitBranch, + label: 'Traces', + }, + { + id: 'memory', + icon: Database, + label: 'Memory', + }, + { + id: 'workflows', + icon: Workflow, + label: 'Workflows', + }, + { + id: 'tools', + icon: Wrench, + label: 'Tools', + }, + { + id: 'prompts', + icon: FileText, + label: 'Prompts', + }, + { + id: 'logs', + icon: Terminal, + label: 'Logs', + }, + { + id: 'analytics', + icon: BarChart3, + label: 'Analytics', + }, +] + +export function Sidebar({ activeView, onViewChange }: SidebarProps) { + return ( +
+
+ {navItems.map((item) => { + const Icon = item.icon + const isActive = activeView === item.id + return ( + + ) + })} +
+ +
+ +
+
+ ) +} diff --git a/packages/dashboard/src/components/Shell/TopBar.tsx b/packages/dashboard/src/components/Shell/TopBar.tsx new file mode 100644 index 000000000..377940abc --- /dev/null +++ b/packages/dashboard/src/components/Shell/TopBar.tsx @@ -0,0 +1,66 @@ +import React from 'react' +import { + Zap, + ChevronRight, + ChevronDown, + Clock, + CheckCircle2, + Star, + Search, + Bell, +} from 'lucide-react' + +export function TopBar() { + return ( +
+
+
+ +
+ VoltAgent + + Core + + + + +
+
+ + http://localhost:3141 + + +
+ +
+ + Connected +
+
+ +
+
+ + +
+
+ 3.5K +
+ +
+
+
+ ) +} diff --git a/packages/dashboard/src/index.css b/packages/dashboard/src/index.css new file mode 100644 index 000000000..82a1fc372 --- /dev/null +++ b/packages/dashboard/src/index.css @@ -0,0 +1,22 @@ +/* @import url() FONT IMPORTS MUST ALWAYS BE AT THE VERY TOP OF THIS FILE, ABOVE THE TAILWIND IMPORTS */ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); + +/* CRITICAL: THE FOLLOWING TAILWIND IMPORTS MUST NEVER BE DELETED OR REORDERED */ +@tailwind base; +@tailwind components; +@tailwind utilities; + +/* END TAILWIND IMPORTS - ALL OTHER CSS MUST GO BELOW THIS LINE */ + +@layer base { + html { + font-family: 'Inter', sans-serif; + } +} + +/* Custom animation for dashed line animation */ +@keyframes dash { + to { + stroke-dashoffset: -100; + } +} diff --git a/packages/dashboard/src/index.tsx b/packages/dashboard/src/index.tsx new file mode 100644 index 000000000..591ded497 --- /dev/null +++ b/packages/dashboard/src/index.tsx @@ -0,0 +1,14 @@ +import './index.css' +import React from 'react' +import { createRoot } from 'react-dom/client' +import { App } from './App' + +const container = document.getElementById('root') +if (container) { + const root = createRoot(container) + root.render( + + + + ) +} diff --git a/packages/dashboard/src/pages/Agents.tsx b/packages/dashboard/src/pages/Agents.tsx new file mode 100644 index 000000000..70afcf15c --- /dev/null +++ b/packages/dashboard/src/pages/Agents.tsx @@ -0,0 +1,151 @@ +import React from 'react' +import { motion } from 'framer-motion' +import { Plus, Bot, Activity, Clock, MoreVertical } from 'lucide-react' + +const mockAgents = [ + { + id: 1, + name: 'InstagramAdCreator', + desc: 'Generates high-converting ad copy and visual prompts for Instagram campaigns.', + model: 'gpt-4o-mini', + status: 'active', + runs: '12.4k', + lastRun: '2m ago', + }, + { + id: 2, + name: 'ResearchAgent', + desc: 'Scrapes web sources and synthesizes research reports on given topics.', + model: 'claude-3-5-sonnet', + status: 'idle', + runs: '3.2k', + lastRun: '1h ago', + }, + { + id: 3, + name: 'CodeReviewer', + desc: 'Analyzes PR diffs and provides automated code review comments.', + model: 'gpt-4o', + status: 'active', + runs: '45.1k', + lastRun: 'Just now', + }, + { + id: 4, + name: 'CustomerSupportBot', + desc: 'Handles tier 1 customer inquiries and routes complex issues to humans.', + model: 'gemini-1.5-pro', + status: 'active', + runs: '89.2k', + lastRun: '5m ago', + }, + { + id: 5, + name: 'DataAnalyzer', + desc: 'Processes CSV/JSON data and generates statistical summaries and charts.', + model: 'gpt-4o-mini', + status: 'failed', + runs: '1.1k', + lastRun: '2h ago', + }, + { + id: 6, + name: 'EmailOutreach', + desc: 'Drafts personalized cold outreach emails based on LinkedIn profiles.', + model: 'claude-3-haiku', + status: 'idle', + runs: '8.5k', + lastRun: '1d ago', + }, +] + +export function Agents() { + return ( +
+
+
+

Agents

+

+ Manage and monitor your deployed AI agents. +

+
+ +
+ +
+ {['All', 'Active', 'Idle', 'Failed'].map((filter, i) => ( + + ))} +
+ +
+ {mockAgents.map((agent, i) => ( + +
+
+
+ +
+
+

+ {agent.name} +

+
+
+ + {agent.status} + +
+
+
+ +
+ +

+ {agent.desc} +

+ +
+ + {agent.model} + +
+ + {agent.runs} + + + {agent.lastRun} + +
+
+
+ ))} +
+
+ ) +} diff --git a/packages/dashboard/src/pages/Analytics.tsx b/packages/dashboard/src/pages/Analytics.tsx new file mode 100644 index 000000000..9653e84bc --- /dev/null +++ b/packages/dashboard/src/pages/Analytics.tsx @@ -0,0 +1,276 @@ +import React from 'react' +import { motion } from 'framer-motion' +import { + AreaChart, + Area, + BarChart, + Bar, + XAxis, + YAxis, + CartesianGrid, + Tooltip, + ResponsiveContainer, +} from 'recharts' +import { Activity, Zap, DollarSign, Target } from 'lucide-react' + +const traceData = [ + { + time: '00:00', + traces: 120, + }, + { + time: '04:00', + traces: 300, + }, + { + time: '08:00', + traces: 850, + }, + { + time: '12:00', + traces: 1200, + }, + { + time: '16:00', + traces: 950, + }, + { + time: '20:00', + traces: 400, + }, +] + +const tokenData = [ + { + name: 'gpt-4o', + tokens: 4000, + }, + { + name: 'claude-3.5', + tokens: 3000, + }, + { + name: 'gemini-1.5', + tokens: 2000, + }, + { + name: 'gpt-4o-mini', + tokens: 8000, + }, +] + +export function Analytics() { + return ( +
+
+

Analytics

+

+ System-wide performance and cost metrics. +

+
+ + {/* Metric Cards */} +
+ {[ + { + label: 'Total Traces (24h)', + value: '142.5K', + change: '+12.5%', + icon: Activity, + color: 'text-blue-500', + }, + { + label: 'Avg Latency', + value: '1.24s', + change: '-5.2%', + icon: Zap, + color: 'text-amber-500', + }, + { + label: 'Total Cost (MTD)', + value: '$842.50', + change: '+2.4%', + icon: DollarSign, + color: 'text-emerald-500', + }, + { + label: 'Success Rate', + value: '99.8%', + change: '+0.1%', + icon: Target, + color: 'text-purple-500', + }, + ].map((stat, i) => { + const Icon = stat.icon + return ( + +
+ + {stat.label} + + +
+
+ + {stat.value} + + + {stat.change} + +
+
+ ) + })} +
+ + {/* Charts */} +
+ +

+ Traces over Time +

+ + + + + + + + + + + + + + + +
+ + +

+ Token Usage by Model +

+ + + + + + + + + +
+
+
+ ) +} diff --git a/packages/dashboard/src/pages/Logs.tsx b/packages/dashboard/src/pages/Logs.tsx new file mode 100644 index 000000000..28903c6a9 --- /dev/null +++ b/packages/dashboard/src/pages/Logs.tsx @@ -0,0 +1,134 @@ +import React from 'react' +import { + Terminal as TerminalIcon, + Play, + Download, + Trash2, +} from 'lucide-react' + +const mockLogs = [ + { + time: '14:22:01.123', + level: 'INFO', + source: 'system', + msg: 'VoltAgent Core initialized successfully on port 3141', + }, + { + time: '14:22:05.441', + level: 'INFO', + source: 'router', + msg: 'Incoming request to /api/v1/agents/InstagramAdCreator/invoke', + }, + { + time: '14:22:05.450', + level: 'DEBUG', + source: 'InstagramAdCreator', + msg: 'Compiling prompt template with variables: {product: "Roku"}', + }, + { + time: '14:22:06.102', + level: 'INFO', + source: 'llm_client', + msg: 'Sending request to OpenAI API (model: gpt-4o-mini)', + }, + { + time: '14:22:08.991', + level: 'INFO', + source: 'llm_client', + msg: 'Received response from OpenAI API (duration: 2.88s, tokens: 450)', + }, + { + time: '14:22:09.015', + level: 'WARN', + source: 'InstagramAdCreator', + msg: 'Output length exceeds recommended limit for Instagram captions', + }, + { + time: '14:22:15.332', + level: 'ERROR', + source: 'DataAnalyzer', + msg: 'Failed to parse JSON output from LLM. Unexpected token < at position 0.', + }, + { + time: '14:22:15.335', + level: 'INFO', + source: 'router', + msg: 'Returning 500 Internal Server Error to client', + }, +] + +export function Logs() { + return ( +
+
+
+

System Logs

+

+ Real-time terminal output from your agent fleet. +

+
+
+ + + +
+
+ +
+
+ + bash - voltagent-core +
+
+ +
+
+ +
+ {mockLogs.map((log, i) => ( +
+ {log.time} + + {log.level} + + + [{log.source}] + + {log.msg} +
+ ))} +
+ _ +
+
+
+
+ ) +} diff --git a/packages/dashboard/src/pages/Observability.tsx b/packages/dashboard/src/pages/Observability.tsx new file mode 100644 index 000000000..546c563ff --- /dev/null +++ b/packages/dashboard/src/pages/Observability.tsx @@ -0,0 +1,405 @@ +import React, { useState } from 'react' +import { motion } from 'framer-motion' +import { + Play, + ChevronRight, + Eye, + Settings, + Maximize2, + Search, + Filter, + Bot, + Clock, +} from 'lucide-react' + +export function Observability() { + const [activeTab, setActiveTab] = useState('Details') + + return ( +
+ {/* Left Column - Trace List */} +
+
+

Live Traces

+
+
+ + +
+ +
+
+
+ {[ + { + id: '1', + name: 'InstagramAdSupervisor', + model: 'gpt-4o-mini', + time: 'Just now', + duration: '1m 24s', + status: 'success', + }, + { + id: '2', + name: 'ResearchAgent', + model: 'claude-3-5', + time: '2m ago', + duration: '45s', + status: 'success', + }, + { + id: '3', + name: 'CodeReviewer', + model: 'gpt-4o', + time: '15m ago', + duration: '2m 10s', + status: 'error', + }, + { + id: '4', + name: 'CustomerSupportBot', + model: 'gemini-1.5', + time: '1h ago', + duration: '12s', + status: 'success', + }, + { + id: '5', + name: 'DataAnalyzer', + model: 'gpt-4o-mini', + time: '2h ago', + duration: '3m 05s', + status: 'warning', + }, + ].map((trace, i) => ( +
+
+
+
+ + {trace.name} + +
+ {trace.time} +
+
+ + {trace.model} + + + {trace.duration} + +
+
+ ))} +
+
+ + {/* Center - Flow Graph */} +
+
+
+ + Execution Flow + + + Trace ID:{' '} + c4ee1nckj7n + +
+
+ +
+
+ + {/* Graph Area */} +
+
+ {/* Connecting Lines */} + + + + + + {/* Node 1: Input */} + +
+
+ {' '} + Input +
+ +
+

+ Create Instagram ad visuals using Google Gemini AI +

+
+
+
+ {' '} + Output +
+ + completed + +
+

+ Here are the generated Instagram ad visuals for the Roku + Streaming Stick Plus 2025... +

+
+
+ + {/* Node 2: InstagramAdCreator */} + +
+
+ + InstagramAdCreator +
+ +
+
+
+ Instructions +
+

+ You are InstagramAdCreator. You are an Instagram advertising + specialist using Google's Gemini AI for ad creation. Your goal + is to generate high-converting visuals. +

+
+
+ +
+ Completed +
+ + Model:{' '} + + gpt-4o-mini + + +
+
+ + {/* Node 3: InstagramAdSupervisor */} + +
+
+ + InstagramAdSupervisor +
+
+
+
+
+
+
+
+ Waiting for input... +
+
+
+
+
+ + {/* Right Column - Inspector */} +
+
+
+
+
+ + InstagramAdCreator + +
+
+ + OK + + +
+
+
+
+ Started: Sep 30, 20:51 +
+
+ Duration: 1m 24s +
+
+ Tokens: 8,749 +
+
+ Cost: $0.012 +
+
+
+ +
+ {['Details', 'Attributes', 'Logs'].map((tab) => ( + + ))} +
+ +
+ {activeTab === 'Details' && ( + <> +
+

+ Key Features +

+
    +
  • Access to all top streaming apps in one place
  • +
  • + Home screen designed for quick access to favorite content +
  • +
  • Works with Alexa, Apple AirPlay and HomeKit
  • +
  • + Supports major streaming services like Apple TV+, Disney+, + Hulu +
  • +
+
+ +
+

+ Call to Action +

+
+ Add to Cart +
+
+ +
+

+ Generated Output +

+
+
+ ROKU +
+
+ Roku Streaming +
+ Stick Plus 2025 +
+
+
+
+
+
+
+

+ 4K streaming made simple. With America's #1 TV streaming + platform, enjoying popular apps is easy and fun. +

+ +
+
+
+ + )} + {activeTab === 'Attributes' && ( +
+ Attributes data... +
+ )} + {activeTab === 'Logs' && ( +
+ Execution logs... +
+ )} +
+
+
+ ) +} diff --git a/packages/dashboard/src/pages/OtherPages.tsx b/packages/dashboard/src/pages/OtherPages.tsx new file mode 100644 index 000000000..96dc2f090 --- /dev/null +++ b/packages/dashboard/src/pages/OtherPages.tsx @@ -0,0 +1,65 @@ +import React from 'react' +import { Database, Workflow, Wrench, FileText } from 'lucide-react' + +export function Memory() { + return ( +
+
+ +
+

+ Vector Memory & Stores +

+

+ Manage long-term memory, vector embeddings, and conversation history for + your agents. +

+
+ ) +} + +export function Workflows() { + return ( +
+
+ +
+

+ Multi-Agent Workflows +

+

+ Design and orchestrate complex workflows involving multiple specialized + agents. +

+
+ ) +} + +export function Tools() { + return ( +
+
+ +
+

Tool Registry

+

+ Register and manage external APIs, functions, and tools that your agents + can invoke. +

+
+ ) +} + +export function Prompts() { + return ( +
+
+ +
+

Prompt Library

+

+ Version control, test, and optimize your system prompts and templates. +

+
+ ) +} diff --git a/packages/dashboard/src/pages/Settings.tsx b/packages/dashboard/src/pages/Settings.tsx new file mode 100644 index 000000000..49c00d732 --- /dev/null +++ b/packages/dashboard/src/pages/Settings.tsx @@ -0,0 +1,107 @@ +import React, { useState } from 'react' +import { Save } from 'lucide-react' + +export function Settings() { + const [activeTab, setActiveTab] = useState('General') + const tabs = [ + 'General', + 'API Keys', + 'Integrations', + 'Team', + 'Billing', + 'Webhooks', + ] + + return ( +
+
+

Settings

+ +
+ +
+ {activeTab === 'General' && ( +
+
+

+ Project Details +

+
+
+ + +
+
+ +