"use client"; import { useState, useEffect, useMemo } from "react"; import { useDefaultLayout } from "react-resizable-panels"; import { Bot, Plus, Archive } from "lucide-react"; import type { CreateAgentRequest, UpdateAgentRequest } from "@multica/core/types"; import { ResizablePanelGroup, ResizablePanel, ResizableHandle, } from "@multica/ui/components/ui/resizable"; import { Button } from "@multica/ui/components/ui/button"; import { toast } from "sonner"; import { Skeleton } from "@multica/ui/components/ui/skeleton"; import { api } from "@multica/core/api"; import { useAuthStore } from "@multica/core/auth"; import { runtimeListOptions } from "@multica/core/runtimes/queries"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useWorkspaceId } from "@multica/core/hooks"; import { agentListOptions, memberListOptions, workspaceKeys } from "@multica/core/workspace/queries"; import { PageHeader } from "../../layout/page-header"; import { CreateAgentDialog } from "./create-agent-dialog"; import { AgentListItem } from "./agent-list-item"; import { AgentDetail } from "./agent-detail"; export function AgentsPage() { const currentUser = useAuthStore((s) => s.user); const qc = useQueryClient(); const wsId = useWorkspaceId(); const { data: agents = [], isLoading } = useQuery(agentListOptions(wsId)); const [selectedId, setSelectedId] = useState(""); const [showArchived, setShowArchived] = useState(false); const [showCreate, setShowCreate] = useState(false); const { data: runtimes = [], isLoading: runtimesLoading } = useQuery(runtimeListOptions(wsId)); const { data: members = [] } = useQuery(memberListOptions(wsId)); const { defaultLayout, onLayoutChanged } = useDefaultLayout({ id: "multica_agents_layout", }); const filteredAgents = useMemo( () => showArchived ? agents.filter((a) => !!a.archived_at) : agents.filter((a) => !a.archived_at), [agents, showArchived], ); const archivedCount = useMemo(() => agents.filter((a) => !!a.archived_at).length, [agents]); // Select first agent on initial load or when filter changes useEffect(() => { if (filteredAgents.length > 0 && !filteredAgents.some((a) => a.id === selectedId)) { setSelectedId(filteredAgents[0]!.id); } }, [filteredAgents, selectedId]); const handleCreate = async (data: CreateAgentRequest) => { const agent = await api.createAgent(data); qc.invalidateQueries({ queryKey: workspaceKeys.agents(wsId) }); setSelectedId(agent.id); }; const handleUpdate = async (id: string, data: Record) => { try { await api.updateAgent(id, data as UpdateAgentRequest); qc.invalidateQueries({ queryKey: workspaceKeys.agents(wsId) }); toast.success("Agent updated"); } catch (e) { toast.error(e instanceof Error ? e.message : "Failed to update agent"); throw e; } }; const handleArchive = async (id: string) => { try { await api.archiveAgent(id); qc.invalidateQueries({ queryKey: workspaceKeys.agents(wsId) }); toast.success("Agent archived"); } catch (e) { toast.error(e instanceof Error ? e.message : "Failed to archive agent"); } }; const handleRestore = async (id: string) => { try { await api.restoreAgent(id); qc.invalidateQueries({ queryKey: workspaceKeys.agents(wsId) }); toast.success("Agent restored"); } catch (e) { toast.error(e instanceof Error ? e.message : "Failed to restore agent"); } }; const selected = agents.find((a) => a.id === selectedId) ?? null; if (isLoading) { return (
{/* List skeleton */}
{Array.from({ length: 4 }).map((_, i) => (
))}
{/* Detail skeleton */}
); } return ( {/* Left column — agent list */}

Agents

{archivedCount > 0 && ( )}
{filteredAgents.length === 0 ? (

{showArchived ? "No archived agents" : archivedCount > 0 ? "No active agents" : "No agents yet"}

{!showArchived && ( )}
) : (
{filteredAgents.map((agent) => ( setSelectedId(agent.id)} /> ))}
)}
{/* Right column — agent detail */} {selected ? ( ) : (

Select an agent to view details

)}
{showCreate && ( setShowCreate(false)} onCreate={handleCreate} /> )}
); }