diff --git a/apps/web/app/(dashboard)/agents/page.tsx b/apps/web/app/(dashboard)/agents/page.tsx index ccca9ff3..49c7e355 100644 --- a/apps/web/app/(dashboard)/agents/page.tsx +++ b/apps/web/app/(dashboard)/agents/page.tsx @@ -1,15 +1,467 @@ -export default function AgentsPage() { +"use client"; + +import { useState } from "react"; +import { + Bot, + Cloud, + Monitor, + Plus, + Wrench, + Blocks, + Zap, + GitBranch, + FileCode, + MessageSquare, + Terminal, + Database, + Globe, + ListTodo, +} from "lucide-react"; +import type { AgentStatus, AgentRuntimeMode } from "@multica/types"; + +// --------------------------------------------------------------------------- +// Types for mock data +// --------------------------------------------------------------------------- + +interface AgentSkill { + id: string; + name: string; + description: string; +} + +interface AgentTool { + id: string; + name: string; + icon: typeof Terminal; + connected: boolean; +} + +interface AgentTask { + id: string; + issueKey: string; + title: string; + status: "working" | "queued"; +} + +interface MockAgent { + id: string; + name: string; + avatar: string; + runtimeMode: AgentRuntimeMode; + status: AgentStatus; + model: string; + description: string; + maxConcurrentTasks: number; + host?: string; + skills: AgentSkill[]; + tools: AgentTool[]; + currentTasks: AgentTask[]; + completedTasks: number; + createdAt: string; +} + +// --------------------------------------------------------------------------- +// Mock data +// --------------------------------------------------------------------------- + +const MOCK_AGENTS: MockAgent[] = [ + { + id: "agent_1", + name: "Claude-1", + avatar: "C1", + runtimeMode: "local", + status: "working", + model: "Claude Sonnet 4", + description: + "General-purpose coding agent for backend development. Specializes in Go API development, database migrations, and test writing.", + maxConcurrentTasks: 2, + host: "jiayuan-macbook", + skills: [ + { + id: "sk_1", + name: "Go API Development", + description: "Build RESTful APIs with Chi, implement CRUD handlers, add middleware", + }, + { + id: "sk_2", + name: "Database Migrations", + description: "Create and run PostgreSQL migrations, update sqlc queries", + }, + { + id: "sk_3", + name: "Test Writing", + description: "Write Go unit and integration tests with testcontainers", + }, + ], + tools: [ + { id: "t_1", name: "GitHub", icon: GitBranch, connected: true }, + { id: "t_2", name: "Terminal", icon: Terminal, connected: true }, + { id: "t_3", name: "PostgreSQL", icon: Database, connected: true }, + { id: "t_4", name: "Browser", icon: Globe, connected: false }, + ], + currentTasks: [ + { + id: "iss_9", + issueKey: "MUL-9", + title: "Implement issue list API endpoint", + status: "working", + }, + { + id: "iss_14", + issueKey: "MUL-14", + title: "Add WebSocket event types for agent status", + status: "queued", + }, + ], + completedTasks: 12, + createdAt: "2026-03-15T10:00:00Z", + }, + { + id: "agent_2", + name: "Codex-1", + avatar: "CX", + runtimeMode: "cloud", + status: "idle", + model: "GPT-5.3 Codex", + description: + "Cloud-hosted coding agent optimized for frontend development. Handles React components, styling, and TypeScript refactoring.", + maxConcurrentTasks: 4, + skills: [ + { + id: "sk_4", + name: "React Components", + description: "Build UI components with React, Radix UI, and Tailwind CSS", + }, + { + id: "sk_5", + name: "TypeScript Refactoring", + description: "Refactor code for type safety, extract shared types and utilities", + }, + ], + tools: [ + { id: "t_5", name: "GitHub", icon: GitBranch, connected: true }, + { id: "t_6", name: "Terminal", icon: Terminal, connected: true }, + { id: "t_7", name: "Browser", icon: Globe, connected: true }, + { id: "t_8", name: "Figma", icon: FileCode, connected: false }, + ], + currentTasks: [], + completedTasks: 8, + createdAt: "2026-03-16T14:00:00Z", + }, + { + id: "agent_3", + name: "Review Bot", + avatar: "RB", + runtimeMode: "cloud", + status: "working", + model: "Claude Sonnet 4", + description: + "Automated code reviewer. Analyzes PRs for correctness, security issues, and adherence to team coding standards.", + maxConcurrentTasks: 8, + skills: [ + { + id: "sk_6", + name: "Code Review", + description: "Review pull requests for bugs, security issues, and style violations", + }, + { + id: "sk_7", + name: "Security Audit", + description: "Check for OWASP top 10 vulnerabilities and insecure patterns", + }, + ], + tools: [ + { id: "t_9", name: "GitHub", icon: GitBranch, connected: true }, + { id: "t_10", name: "Comments", icon: MessageSquare, connected: true }, + ], + currentTasks: [ + { + id: "iss_pr47", + issueKey: "PR-47", + title: "Review: Add WebSocket reconnection logic", + status: "working", + }, + ], + completedTasks: 34, + createdAt: "2026-03-14T09:00:00Z", + }, + { + id: "agent_4", + name: "Claude-2", + avatar: "C2", + runtimeMode: "local", + status: "offline", + model: "Claude Sonnet 4", + description: + "Secondary local agent on Bohan's machine. Used for documentation and knowledge base tasks.", + maxConcurrentTasks: 1, + host: "bohan-macbook", + skills: [ + { + id: "sk_8", + name: "Documentation", + description: "Write and update technical docs, API references, and README files", + }, + ], + tools: [ + { id: "t_11", name: "GitHub", icon: GitBranch, connected: true }, + { id: "t_12", name: "Terminal", icon: Terminal, connected: true }, + ], + currentTasks: [], + completedTasks: 5, + createdAt: "2026-03-18T16:00:00Z", + }, +]; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +const statusConfig: Record = { + idle: { label: "Idle", color: "text-muted-foreground", dot: "bg-muted-foreground" }, + working: { label: "Working", color: "text-green-600", dot: "bg-green-500" }, + blocked: { label: "Blocked", color: "text-yellow-600", dot: "bg-yellow-500" }, + error: { label: "Error", color: "text-red-600", dot: "bg-red-500" }, + offline: { label: "Offline", color: "text-muted-foreground/50", dot: "bg-muted-foreground/40" }, +}; + +// --------------------------------------------------------------------------- +// Components +// --------------------------------------------------------------------------- + +function AgentListItem({ + agent, + isSelected, + onClick, +}: { + agent: MockAgent; + isSelected: boolean; + onClick: () => void; +}) { + const st = statusConfig[agent.status]; + return ( -
-
-

Agents

- + + ); +} + +function SectionHeader({ + icon: Icon, + title, + count, +}: { + icon: typeof Wrench; + title: string; + count?: number; +}) { + return ( +
+ +

{title}

+ {count !== undefined && ( + ({count}) + )} +
+ ); +} + +function AgentDetail({ agent }: { agent: MockAgent }) { + const st = statusConfig[agent.status]; + + return ( +
+ {/* Header */} +
+
+ {agent.avatar} +
+
+
+

{agent.name}

+ + + {st.label} + +
+

{agent.description}

+
+
+ + {/* Meta info */} +
+
+
Runtime
+
+ {agent.runtimeMode === "cloud" ? ( + + ) : ( + + )} + {agent.runtimeMode === "cloud" ? "Cloud" : "Local"} + {agent.host && ( + ({agent.host}) + )} +
+
+
+
Model
+
{agent.model}
+
+
+
Concurrency
+
+ {agent.currentTasks.filter((t) => t.status === "working").length} / {agent.maxConcurrentTasks} slots +
+
+
+
Completed Tasks
+
{agent.completedTasks}
+
+
+ + {/* Skills */} +
+ +
+ {agent.skills.map((skill) => ( +
+
{skill.name}
+
+ {skill.description} +
+
+ ))} +
+
+ + {/* Connected Tools */} +
+ +
+ {agent.tools.map((tool) => ( +
+ + {tool.name} + {tool.connected ? ( + Connected + ) : ( + Not set up + )} +
+ ))} +
+
+ + {/* Current Tasks */} +
+ + {agent.currentTasks.length > 0 ? ( +
+ {agent.currentTasks.map((task) => ( +
+ + {task.issueKey} + + {task.title} + + {task.status === "working" ? "Working" : "Queued"} + +
+ ))} +
+ ) : ( +

No active tasks

+ )} +
+
+ ); +} + +// --------------------------------------------------------------------------- +// Page +// --------------------------------------------------------------------------- + +export default function AgentsPage() { + const [selectedId, setSelectedId] = useState(MOCK_AGENTS[0]?.id ?? ""); + const selected = MOCK_AGENTS.find((a) => a.id === selectedId) ?? null; + + return ( +
+ {/* Left column — agent list */} +
+
+

Agents

+ +
+
+ {MOCK_AGENTS.map((agent) => ( + setSelectedId(agent.id)} + /> + ))} +
+
+ + {/* Right column — agent detail */} +
+ {selected ? ( + + ) : ( +
+ Select an agent to view details +
+ )}
-

- No agents configured yet. Add your first agent to start automating tasks. -

); }