From 50e19bcdac0a4a77078080ecb3f6342870dae912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Salavisa?= Date: Sat, 14 Mar 2026 10:10:16 +0000 Subject: [PATCH] feat(settings): move utility agents to main agents page (#436) * feat(settings): move utility agents to main agents page - Extract utility agents section into reusable component - Add utility agents section to main agents settings page - Remove separate utility agents page and sidebar link - Consolidate all agent-related settings in one location * style: format utility-agents-section.tsx with prettier * fix: add error handling for utility agents operations - Add try/catch with rollback for handleDefaultChange - Add try/catch for onDelete to prevent UI inconsistency on failure Addresses CodeRabbit review comments. --- apps/web/app/settings/agents/page.tsx | 3 + .../settings/settings-app-sidebar.tsx | 11 --- .../settings/utility-agents-section.tsx} | 92 +++++++++++-------- 3 files changed, 55 insertions(+), 51 deletions(-) rename apps/web/{app/settings/utility/page.tsx => components/settings/utility-agents-section.tsx} (66%) diff --git a/apps/web/app/settings/agents/page.tsx b/apps/web/app/settings/agents/page.tsx index 0adeda507e..1c5cd08b5f 100644 --- a/apps/web/app/settings/agents/page.tsx +++ b/apps/web/app/settings/agents/page.tsx @@ -29,6 +29,7 @@ import { useAgentDiscovery } from "@/hooks/domains/settings/use-agent-discovery" import { useAvailableAgents } from "@/hooks/domains/settings/use-available-agents"; import { AgentLogo } from "@/components/agent-logo"; import { AddTUIAgentDialog } from "@/components/settings/add-tui-agent-dialog"; +import { UtilityAgentsSection } from "@/components/settings/utility-agents-section"; import { toAgentProfileOption } from "@/lib/state/slices/settings/types"; import type { AgentDiscovery, @@ -565,6 +566,8 @@ export default function AgentsSettingsPage() { + + - {/* Utility Agents */} - - - - - Utility Agents - - - - diff --git a/apps/web/app/settings/utility/page.tsx b/apps/web/components/settings/utility-agents-section.tsx similarity index 66% rename from apps/web/app/settings/utility/page.tsx rename to apps/web/components/settings/utility-agents-section.tsx index f008f5560e..28eadf0e4c 100644 --- a/apps/web/app/settings/utility/page.tsx +++ b/apps/web/components/settings/utility-agents-section.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useState, useCallback, useMemo } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { Separator } from "@kandev/ui/separator"; import { listUtilityAgents, @@ -43,7 +43,7 @@ async function handleBuiltinChange( ); } -export default function UtilityAgentsSettingsPage() { +export function UtilityAgentsSection() { const [agents, setAgents] = useState([]); const [inferenceAgents, setInferenceAgents] = useState([]); const [defaultAgentId, setDefaultAgentId] = useState(""); @@ -75,14 +75,17 @@ export default function UtilityAgentsSettingsPage() { } }, []); - useEffect(() => { - fetchData(); - }, [fetchData]); - const handleDefaultChange = async (agentId: string, model: string) => { + const prevAgentId = defaultAgentId; + const prevModel = defaultModel; setDefaultAgentId(agentId); setDefaultModel(model); - await updateUserSettings({ default_utility_agent_id: agentId, default_utility_model: model }); + try { + await updateUserSettings({ default_utility_agent_id: agentId, default_utility_model: model }); + } catch { + setDefaultAgentId(prevAgentId); + setDefaultModel(prevModel); + } }; const openEditDialog = (agent: UtilityAgent | null) => { @@ -96,46 +99,55 @@ export default function UtilityAgentsSettingsPage() { fetchData(); }; - if (loading) - return
Loading...
; + useEffect(() => { + fetchData(); + }, [fetchData]); + + if (loading) return null; return ( -
-
-

Utility Agents

-

- One-shot AI helpers for commits, PRs, and prompts. -

-
- - - handleBuiltinChange(agent, value, setAgents)} - onEdit={openEditDialog} - /> - openEditDialog(null)} - onEdit={openEditDialog} - onDelete={async (agent) => { - await deleteUtilityAgent(agent.id); - setAgents((prev) => prev.filter((a) => a.id !== agent.id)); - }} - /> + <> +
+ +
+

Utility Agents

+

+ One-shot AI helpers for commits, PRs, and prompts. +

+
+ + handleBuiltinChange(agent, value, setAgents)} + onEdit={openEditDialog} + /> + openEditDialog(null)} + onEdit={openEditDialog} + onDelete={async (agent) => { + try { + await deleteUtilityAgent(agent.id); + setAgents((prev) => prev.filter((a) => a.id !== agent.id)); + } catch { + // Error already logged by API layer + } + }} + /> +
-
+ ); }