From f69aa93a757ea09e61bb2ff0182904085d15907e Mon Sep 17 00:00:00 2001 From: Jiayuan Date: Tue, 31 Mar 2026 14:40:53 +0800 Subject: [PATCH] feat(agents): add Settings tab for editing agent visibility and properties Adds a Settings tab to the agent detail panel with: - Name and description editing - Visibility toggle (workspace/private) matching the create dialog pattern - Max concurrent tasks configuration - Runtime info display (read-only) --- apps/web/app/(dashboard)/agents/page.tsx | 143 ++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/apps/web/app/(dashboard)/agents/page.tsx b/apps/web/app/(dashboard)/agents/page.tsx index 902cbcf4..dce100c4 100644 --- a/apps/web/app/(dashboard)/agents/page.tsx +++ b/apps/web/app/(dashboard)/agents/page.tsx @@ -27,6 +27,7 @@ import { ChevronDown, Globe, Lock, + Settings, } from "lucide-react"; import type { Agent, @@ -1151,11 +1152,143 @@ function TasksTab({ agent }: { agent: Agent }) { ); } +// --------------------------------------------------------------------------- +// Settings Tab +// --------------------------------------------------------------------------- + +function SettingsTab({ + agent, + runtimes, + onSave, +}: { + agent: Agent; + runtimes: RuntimeDevice[]; + onSave: (updates: Partial) => Promise; +}) { + const [name, setName] = useState(agent.name); + const [description, setDescription] = useState(agent.description ?? ""); + const [visibility, setVisibility] = useState(agent.visibility); + const [maxTasks, setMaxTasks] = useState(agent.max_concurrent_tasks); + const [saving, setSaving] = useState(false); + + const dirty = + name !== agent.name || + description !== (agent.description ?? "") || + visibility !== agent.visibility || + maxTasks !== agent.max_concurrent_tasks; + + const handleSave = async () => { + if (!name.trim()) { + toast.error("Name is required"); + return; + } + setSaving(true); + try { + await onSave({ name: name.trim(), description, visibility, max_concurrent_tasks: maxTasks }); + toast.success("Settings saved"); + } catch { + toast.error("Failed to save settings"); + } finally { + setSaving(false); + } + }; + + const runtimeDevice = runtimes.find((r) => r.id === agent.runtime_id); + + return ( +
+
+ + setName(e.target.value)} + className="mt-1" + /> +
+ +
+ + setDescription(e.target.value)} + placeholder="What does this agent do?" + className="mt-1" + /> +
+ +
+ +
+ + +
+
+ +
+ + setMaxTasks(Number(e.target.value))} + className="mt-1 w-24" + /> +
+ +
+ +
+ {agent.runtime_mode === "cloud" ? ( + + ) : ( + + )} + {runtimeDevice?.name ?? (agent.runtime_mode === "cloud" ? "Cloud" : "Local")} +
+
+ + +
+ ); +} + // --------------------------------------------------------------------------- // Agent Detail // --------------------------------------------------------------------------- -type DetailTab = "instructions" | "skills" | "tools" | "triggers" | "tasks"; +type DetailTab = "instructions" | "skills" | "tools" | "triggers" | "tasks" | "settings"; const detailTabs: { id: DetailTab; label: string; icon: typeof FileText }[] = [ { id: "instructions", label: "Instructions", icon: FileText }, @@ -1163,6 +1296,7 @@ const detailTabs: { id: DetailTab; label: string; icon: typeof FileText }[] = [ { id: "tools", label: "Tools", icon: Wrench }, { id: "triggers", label: "Triggers", icon: Timer }, { id: "tasks", label: "Tasks", icon: ListTodo }, + { id: "settings", label: "Settings", icon: Settings }, ]; function AgentDetail({ @@ -1267,6 +1401,13 @@ function AgentDetail({ /> )} {activeTab === "tasks" && } + {activeTab === "settings" && ( + onUpdate(agent.id, updates)} + /> + )} {/* Delete Confirmation */}