diff --git a/ui/src/pages/AgentDetail.tsx b/ui/src/pages/AgentDetail.tsx index 554d271e..dd434ffb 100644 --- a/ui/src/pages/AgentDetail.tsx +++ b/ui/src/pages/AgentDetail.tsx @@ -34,6 +34,7 @@ import { ScrollToBottom } from "../components/ScrollToBottom"; import { formatCents, formatDate, relativeTime, formatTokens, visibleRunCostUsd } from "../lib/utils"; import { cn } from "../lib/utils"; import { Button } from "@/components/ui/button"; +import { Skeleton } from "@/components/ui/skeleton"; import { Tabs } from "@/components/ui/tabs"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { @@ -217,6 +218,14 @@ function usageNumber(usage: Record | null, ...keys: string[]) { return 0; } +function setsEqual(left: Set, right: Set) { + if (left.size !== right.size) return false; + for (const value of left) { + if (!right.has(value)) return false; + } + return true; +} + function runMetrics(run: HeartbeatRun) { const usage = (run.usageJson ?? null) as Record | null; const result = (run.resultJson ?? null) as Record | null; @@ -1517,7 +1526,10 @@ function PromptsTab({ const currentMode = bundleDraft?.mode ?? bundle?.mode ?? "managed"; const currentEntryFile = bundleDraft?.entryFile ?? bundle?.entryFile ?? "AGENTS.md"; const currentRootPath = bundleDraft?.rootPath ?? bundle?.rootPath ?? ""; - const fileOptions = bundle?.files.map((file) => file.path) ?? []; + const fileOptions = useMemo( + () => bundle?.files.map((file) => file.path) ?? [], + [bundle], + ); const visibleFilePaths = useMemo( () => [...new Set([currentEntryFile, ...fileOptions])], [currentEntryFile, fileOptions], @@ -1606,7 +1618,7 @@ function PromptsTab({ nextExpanded.add(currentPath); } } - setExpandedDirs(nextExpanded); + setExpandedDirs((current) => (setsEqual(current, nextExpanded) ? current : nextExpanded)); }, [visibleFilePaths]); useEffect(() => { @@ -1712,7 +1724,7 @@ function PromptsTab({ } if (bundleLoading && !bundle) { - return
Loading instructions bundle…
; + return ; } return ( @@ -1922,7 +1934,7 @@ function PromptsTab({ {selectedFileExists && fileLoading && !selectedFileDetail ? ( -

Loading file…

+ ) : isMarkdown(selectedOrEntryFile) ? ( +
+
+
+ + +
+ +
+
+ {Array.from({ length: 3 }).map((_, index) => ( +
+ + +
+ ))} +
+
+
+
+
+ + +
+ +
+ {Array.from({ length: 5 }).map((_, index) => ( + + ))} +
+
+
+
+ + +
+ +
+
+ + ); +} + +function PromptEditorSkeleton() { + return ( +
+ + +
+ ); +} + function AgentSkillsTab({ agent, companyId,