// ============================================================================ // public/screens/agents.jsx — Agent library (list + create modal) // ---------------------------------------------------------------------------- // Cards-on-grid layout matching the mockup. Each card shows avatar gradient, // name, role, language, LLM, status badge, and total calls. // Phase 4 will add the full agent editor (prompt, voice, flow); for now we // support: list, create with basic fields, activate/archive, delete. // ============================================================================ function AgentsScreen({ go }) { const [agents, setAgents] = React.useState(null); const [error, setError] = React.useState(null); const [showCreate, setShow] = React.useState(false); const load = React.useCallback(() => { setError(null); VoaisAPI.get("/api/agents").then((r) => { if (r.ok && r.data?.ok) setAgents(r.data.agents); else setError(r.data?.msg || "Failed to load agents."); }); }, []); React.useEffect(load, [load]); const handleStatus = async (id, status) => { await VoaisAPI.patch("/api/agents/" + id, { status }); load(); }; const handleDelete = async (id) => { if (!confirm("Delete this agent? This cannot be undone.")) return; const r = await VoaisAPI.del("/api/agents/" + id); if (!r.ok) { alert(r.data?.msg || "Delete failed."); return; } load(); }; if (agents === null && !error) return ; return (
{/* Header */}
{agents?.length || 0} agents
} onClick={() => setShow(true)}>New agent
{error && (
{error}
)} {/* Empty state */} {agents?.length === 0 && !error && (

No agents yet

Agents are the AI personas that handle your calls. Create your first one — give it a name, a role, and a voice — and you'll be ready to launch campaigns.

} onClick={() => setShow(true)}>Create your first agent
)} {/* Grid */} {agents && agents.length > 0 && (
{agents.map((a) => ( ))}
)} {showCreate && setShow(false)} onCreated={() => { setShow(false); load(); }}/>}
); } // ── Agent card ────────────────────────────────────────────────────────── function AgentCard({ agent, onStatusChange, onDelete }) { const grad = agent.avatar_gradient || "linear-gradient(135deg,#5B8FFF,#00D49F)"; const statusTone = agent.status === "active" ? "green" : agent.status === "draft" ? "gray" : "yellow"; return ( {/* Coloured header */}
{(agent.name || "?").charAt(0).toUpperCase()}
{agent.status}

{agent.name}

· {agent.code}
{agent.role || "—"}
{agent.language || "—"} {agent.llm_provider} · {agent.llm_model}
Calls handled
{Number(agent.total_calls || 0).toLocaleString("en-IN")}
Success rate
{agent.success_rate ? `${Number(agent.success_rate)}%` : "—"}
{agent.status === "draft" && ( onStatusChange(agent.id, "active")}>Activate )} {agent.status === "active" && ( onStatusChange(agent.id, "archived")}>Archive )} {agent.status === "archived" && ( onStatusChange(agent.id, "active")}>Restore )} onDelete(agent.id)} title="Delete">
); } // ── Create agent modal ────────────────────────────────────────────────── function CreateAgentModal({ onClose, onCreated }) { const [form, setForm] = React.useState({ name: "", role: "", description: "", language: "hinglish", llm_provider: "gemini", llm_model: "gemini-1.5-pro", system_prompt: "", opening_script: "", }); const [submitting, setSubmitting] = React.useState(false); const [err, setErr] = React.useState(null); const submit = async (e) => { e.preventDefault(); setErr(null); if (!form.name.trim()) return setErr("Name is required."); setSubmitting(true); const r = await VoaisAPI.post("/api/agents", form); setSubmitting(false); if (r.ok) onCreated(); else setErr(r.data?.msg || "Failed to create agent."); }; return (
{err &&
{err}
} setForm({ ...form, name: e.target.value })}/> setForm({ ...form, role: e.target.value })}/>