"use client"; /* Agents: preset list + the Agent config (flavor · model · tools · middleware stack). */ import { useCallback, useEffect, useState } from "react"; import { Icon } from "../icons"; import { StatusPill, Tile } from "../primitives"; import { AgentConfig } from "../canvas/AgentConfig"; import { VersionHistory } from "../version-history"; import { ImportExport } from "../import-export"; import { api, Agent, ComponentT, McpClientT, Tool, ToolSet } from "@/lib/api"; const NEW_AGENT_CONFIG = { flavor: "agent", model: "openai:gpt-4o-mini", system_prompt: "", tools: [], components: [], middleware: [] }; /* ============ AGENTS LIST ============ */ export function AgentsScreen({ project, onOpen }: { project: any; onOpen: (a: Agent) => void }) { const [agents, setAgents] = useState([]); const [loaded, setLoaded] = useState(false); const [busy, setBusy] = useState(false); const reload = useCallback(() => { if (!project?.id) return; api.listAgents(project.id).then((a) => { setAgents(a); setLoaded(true); }).catch(() => setLoaded(true)); }, [project?.id]); useEffect(() => { reload(); }, [reload]); async function create() { setBusy(true); try { const a = await api.createAgent(project.id, { name: "new_agent", config: NEW_AGENT_CONFIG }); onOpen(a); } finally { setBusy(false); } } const [deleting, setDeleting] = useState(null); async function del(e: React.MouseEvent, a: Agent) { e.stopPropagation(); if (!window.confirm(`Delete agent "${a.name}"? This cannot be undone.`)) return; setDeleting(a.id); try { setAgents((prev) => prev.filter((x) => x.id !== a.id)); // optimistic await api.deleteAgent(project.id, a.id); } catch { reload(); } finally { setDeleting(null); } } return (
Agents
Reusable agent presets - model, tools, and a middleware stack. Drop them into workflows.
({ id: a.id, name: a.name, sub: `${a.config?.flavor || "agent"} · ${a.config?.model || "-"}` }))} />
{loaded && agents.length === 0 ? (
No agent presets yet
Create a reusable agent with its own model, tools, and middleware stack.
) : (
{agents.map((a) => { const c = a.config || {}; const tools = (c.tools || []).length; const mw = (c.middleware || []).filter((m: any) => m.enabled !== false).length; return (
onOpen(a)}>
{a.name}{c.flavor || "agent"}
{c.model || "-"} · {tools} tools · {mw} middleware{a.created_by_email ? ` · by ${a.created_by_email}` : ""}
); })}
)}
); } /* ============ AGENT CONFIG ============ */ export function AgentConfigScreen({ project, agentId, onBack }: { project: any; agentId?: string; onBack: () => void }) { const [agent, setAgent] = useState(null); const [config, setConfig] = useState>(NEW_AGENT_CONFIG); const [name, setName] = useState(""); const [tools, setTools] = useState([]); const [toolSets, setToolSets] = useState([]); const [mcpServers, setMcpServers] = useState([]); const [components, setComponents] = useState([]); const [folders, setFolders] = useState([]); const [kinds, setKinds] = useState([]); const [save, setSave] = useState<"idle" | "saving" | "saved">("idle"); const [reloadKey, setReloadKey] = useState(0); useEffect(() => { if (project?.id) api.listTools(project.id).then(setTools).catch(() => {}); if (project?.id) api.listToolSets(project.id).then(setToolSets).catch(() => {}); if (project?.id) api.listMcpClients(project.id).then(setMcpServers).catch(() => {}); if (project?.id) api.listComponents(project.id).then(setComponents).catch(() => {}); if (project?.id) api.listFolders(project.id).then(setFolders).catch(() => {}); if (project?.id) api.listQaKinds(project.id).then(setKinds).catch(() => {}); if (project?.id && agentId) api.getAgent(project.id, agentId).then((a) => { setAgent(a); setConfig(a.config || NEW_AGENT_CONFIG); setName(a.name); }).catch(() => {}); }, [project?.id, agentId, reloadKey]); async function persist() { if (!agent) return; setSave("saving"); await api.updateAgent(project.id, agent.id, { name, config }); setSave("saved"); setTimeout(() => setSave("idle"), 1400); } return (
setName(e.target.value)} placeholder="agent_name" /> {agent?.created_by_email && ( Created by {agent.created_by_email} )}
setReloadKey((k) => k + 1)} />
What the model sees
System prompt
{config.system_prompt || - none -}
Compiled stack (execution order)
{(config.middleware || []).filter((m: any) => m.enabled !== false).map((m: any, i: number) => (
{i + 1}{m.type}
))} {(config.middleware || []).filter((m: any) => m.enabled !== false).length === 0 &&
No middleware
}
); }