import { useState, useEffect } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { useNavigate } from "react-router-dom"; import { useDialog } from "../context/DialogContext"; import { useCompany } from "../context/CompanyContext"; import { agentsApi } from "../api/agents"; import { queryKeys } from "../lib/queryKeys"; import { AGENT_ROLES } from "@paperclip/shared"; import { Dialog, DialogContent, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { Minimize2, Maximize2, Shield, User, } from "lucide-react"; import { cn } from "../lib/utils"; import { roleLabels } from "./agent-config-primitives"; import { AgentConfigForm, type CreateConfigValues } from "./AgentConfigForm"; import { defaultCreateValues } from "./agent-config-defaults"; import { getUIAdapter } from "../adapters"; import { AgentIcon } from "./AgentIconPicker"; export function NewAgentDialog() { const { newAgentOpen, closeNewAgent } = useDialog(); const { selectedCompanyId, selectedCompany } = useCompany(); const queryClient = useQueryClient(); const navigate = useNavigate(); const [expanded, setExpanded] = useState(true); // Identity const [name, setName] = useState(""); const [title, setTitle] = useState(""); const [role, setRole] = useState("general"); const [reportsTo, setReportsTo] = useState(""); // Config values (managed by AgentConfigForm) const [configValues, setConfigValues] = useState(defaultCreateValues); // Popover states const [roleOpen, setRoleOpen] = useState(false); const [reportsToOpen, setReportsToOpen] = useState(false); const { data: agents } = useQuery({ queryKey: queryKeys.agents.list(selectedCompanyId!), queryFn: () => agentsApi.list(selectedCompanyId!), enabled: !!selectedCompanyId && newAgentOpen, }); const { data: adapterModels } = useQuery({ queryKey: ["adapter-models", configValues.adapterType], queryFn: () => agentsApi.adapterModels(configValues.adapterType), enabled: newAgentOpen, }); const isFirstAgent = !agents || agents.length === 0; const effectiveRole = isFirstAgent ? "ceo" : role; // Auto-fill for CEO useEffect(() => { if (newAgentOpen && isFirstAgent) { if (!name) setName("CEO"); if (!title) setTitle("CEO"); } }, [newAgentOpen, isFirstAgent]); // eslint-disable-line react-hooks/exhaustive-deps const createAgent = useMutation({ mutationFn: (data: Record) => agentsApi.hire(selectedCompanyId!, data), onSuccess: (result) => { queryClient.invalidateQueries({ queryKey: queryKeys.agents.list(selectedCompanyId!) }); queryClient.invalidateQueries({ queryKey: queryKeys.approvals.list(selectedCompanyId!) }); reset(); closeNewAgent(); navigate(`/agents/${result.agent.id}`); }, }); function reset() { setName(""); setTitle(""); setRole("general"); setReportsTo(""); setConfigValues(defaultCreateValues); setExpanded(true); } function buildAdapterConfig() { const adapter = getUIAdapter(configValues.adapterType); return adapter.buildAdapterConfig(configValues); } function handleSubmit() { if (!selectedCompanyId || !name.trim()) return; createAgent.mutate({ name: name.trim(), role: effectiveRole, ...(title.trim() ? { title: title.trim() } : {}), ...(reportsTo ? { reportsTo } : {}), adapterType: configValues.adapterType, adapterConfig: buildAdapterConfig(), runtimeConfig: { heartbeat: { enabled: configValues.heartbeatEnabled, intervalSec: configValues.intervalSec, wakeOnDemand: true, cooldownSec: 10, maxConcurrentRuns: 1, }, }, budgetMonthlyCents: 0, }); } function handleKeyDown(e: React.KeyboardEvent) { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); handleSubmit(); } } const currentReportsTo = (agents ?? []).find((a) => a.id === reportsTo); return ( { if (!open) { reset(); closeNewAgent(); } }} > {/* Header */}
{selectedCompany && ( {selectedCompany.name.slice(0, 3).toUpperCase()} )} New agent
{/* Name */}
setName(e.target.value)} autoFocus />
{/* Title */}
setTitle(e.target.value)} />
{/* Property chips: Role + Reports To */}
{/* Role */} {AGENT_ROLES.map((r) => ( ))} {/* Reports To */} {(agents ?? []).map((a) => ( ))}
{/* Shared config form (adapter + heartbeat) */} setConfigValues((prev) => ({ ...prev, ...patch }))} adapterModels={adapterModels} />
{/* Footer */}
{isFirstAgent ? "This will be the CEO" : ""}
); }