diff --git a/desktop/src/features/agents/hooks.ts b/desktop/src/features/agents/hooks.ts index d9461b730b7..a99ae1c768c 100644 --- a/desktop/src/features/agents/hooks.ts +++ b/desktop/src/features/agents/hooks.ts @@ -95,6 +95,7 @@ export function usePersonasQuery() { queryKey: personasQueryKey, queryFn: listPersonas, staleTime: 30_000, + refetchInterval: 30_000, }); } @@ -125,6 +126,7 @@ export function useRelayAgentsQuery() { queryKey: relayAgentsQueryKey, queryFn: listRelayAgents, staleTime: 15_000, + refetchInterval: 15_000, }); } diff --git a/desktop/src/features/agents/ui/AgentsView.tsx b/desktop/src/features/agents/ui/AgentsView.tsx index 39e1378fb11..7611d1143dd 100644 --- a/desktop/src/features/agents/ui/AgentsView.tsx +++ b/desktop/src/features/agents/ui/AgentsView.tsx @@ -261,12 +261,6 @@ export function AgentsView() { void relayAgentsQuery.refetch(); } - function handleRefresh() { - void managedAgentsQuery.refetch(); - void relayAgentsQuery.refetch(); - void managedAgentLogQuery.refetch(); - } - const isActionPending = startMutation.isPending || stopMutation.isPending || @@ -341,9 +335,6 @@ export function AgentsView() { }, }); }} - onRefresh={() => { - void personasQuery.refetch(); - }} personas={personas} /> @@ -373,7 +364,6 @@ export function AgentsView() { onMintToken={(pubkey, name) => { void handleMintToken(pubkey, name); }} - onRefresh={handleRefresh} onStart={(pubkey) => { void handleStart(pubkey); }} diff --git a/desktop/src/features/agents/ui/CreateAgentDialogSections.tsx b/desktop/src/features/agents/ui/CreateAgentDialogSections.tsx index 9850c877b63..1677d2f71d4 100644 --- a/desktop/src/features/agents/ui/CreateAgentDialogSections.tsx +++ b/desktop/src/features/agents/ui/CreateAgentDialogSections.tsx @@ -296,7 +296,7 @@ export function CreateAgentOptionToggles({ type="button" >

Mint token

-

+

{prereqs !== null && !isMintSupported ? `Unavailable until ${prereqs.admin.command} is installed.` : "Use `sprout-admin` to create a bearer token for this agent."} @@ -317,7 +317,7 @@ export function CreateAgentOptionToggles({

Start on app launch

-

+

Reopen this local ACP harness automatically when the desktop app starts.

@@ -339,7 +339,7 @@ export function CreateAgentOptionToggles({

Spawn after create

-

+

{prereqs !== null && !isSpawnSupported ? "Requires both the ACP harness and MCP server binaries." : "Start the local ACP harness immediately after the profile is saved."} @@ -392,6 +392,9 @@ export function CreateAgentTokenSection({ type="button" > {scope.label} + + {scope.description} + ); })} diff --git a/desktop/src/features/agents/ui/ManagedAgentsSection.tsx b/desktop/src/features/agents/ui/ManagedAgentsSection.tsx index 2c64edd3f2f..9a358676e4f 100644 --- a/desktop/src/features/agents/ui/ManagedAgentsSection.tsx +++ b/desktop/src/features/agents/ui/ManagedAgentsSection.tsx @@ -6,7 +6,6 @@ import { Play, Plus, Power, - RefreshCcw, Square, Trash2, UserPlus, @@ -23,6 +22,7 @@ import { DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; import { Skeleton } from "@/shared/ui/skeleton"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/ui/tooltip"; import { ModelPicker } from "./ModelPicker"; import { truncatePubkey } from "./agentUi"; @@ -38,7 +38,6 @@ export function ManagedAgentsSection({ onCreate, onDelete, onMintToken, - onRefresh, onStart, onStop, onToggleStartOnAppLaunch, @@ -55,7 +54,6 @@ export function ManagedAgentsSection({ onCreate: () => void; onDelete: (pubkey: string) => void; onMintToken: (pubkey: string, name: string) => void; - onRefresh: () => void; onStart: (pubkey: string) => void; onStop: (pubkey: string) => void; onToggleStartOnAppLaunch: (pubkey: string, startOnAppLaunch: boolean) => void; @@ -72,16 +70,20 @@ export function ManagedAgentsSection({ Saved agent profiles and local ACP process state.

-
- - -
+ + + + + Create agent + {isLoading ? ( @@ -138,7 +140,6 @@ export function ManagedAgentsSection({ onAddToChannel={onAddToChannel} onDelete={onDelete} onMintToken={onMintToken} - onModelChanged={onRefresh} onStart={onStart} onStop={onStop} onToggleStartOnAppLaunch={onToggleStartOnAppLaunch} @@ -179,7 +180,6 @@ function ManagedAgentRow({ onAddToChannel, onDelete, onMintToken, - onModelChanged, onStart, onStop, onToggleStartOnAppLaunch, @@ -191,7 +191,6 @@ function ManagedAgentRow({ onAddToChannel: (agent: ManagedAgent) => void; onDelete: (pubkey: string) => void; onMintToken: (pubkey: string, name: string) => void; - onModelChanged?: () => void; onStart: (pubkey: string) => void; onStop: (pubkey: string) => void; onToggleStartOnAppLaunch: (pubkey: string, startOnAppLaunch: boolean) => void; @@ -233,7 +232,7 @@ function ManagedAgentRow({ - + {agent.agentCommand} diff --git a/desktop/src/features/agents/ui/PersonasSection.tsx b/desktop/src/features/agents/ui/PersonasSection.tsx index 99e9fe6a6dd..186689251ea 100644 --- a/desktop/src/features/agents/ui/PersonasSection.tsx +++ b/desktop/src/features/agents/ui/PersonasSection.tsx @@ -1,11 +1,4 @@ -import { - CopyPlus, - Ellipsis, - Pencil, - Plus, - RefreshCcw, - Trash2, -} from "lucide-react"; +import { CopyPlus, Ellipsis, Info, Pencil, Plus, Trash2 } from "lucide-react"; import { ProfileAvatar } from "@/features/profile/ui/ProfileAvatar"; import type { AgentPersona } from "@/shared/api/types"; @@ -17,13 +10,18 @@ import { DropdownMenuTrigger, } from "@/shared/ui/dropdown-menu"; import { Skeleton } from "@/shared/ui/skeleton"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/ui/tooltip"; function promptPreview(systemPrompt: string) { - const [firstLine] = systemPrompt + const trimmed = systemPrompt.trim(); + if (!trimmed) { + return null; + } + const [firstLine] = trimmed .split("\n") .map((line) => line.trim()) .filter((line) => line.length > 0); - return firstLine ?? systemPrompt.trim(); + return firstLine ?? trimmed; } type PersonasSectionProps = { @@ -35,7 +33,6 @@ type PersonasSectionProps = { onDuplicate: (persona: AgentPersona) => void; onEdit: (persona: AgentPersona) => void; onDelete: (persona: AgentPersona) => void; - onRefresh: () => void; }; export function PersonasSection({ @@ -47,7 +44,6 @@ export function PersonasSection({ onDuplicate, onEdit, onDelete, - onRefresh, }: PersonasSectionProps) { return (
@@ -58,114 +54,133 @@ export function PersonasSection({ Reusable agent templates for common roles and prompts.

-
- - -
+ + + + + Create persona + {isLoading ? ( -
- {["first", "second", "third", "fourth"].map((key) => ( +
+ {["first", "second", "third", "fourth", "fifth"].map((key) => (
- +
-
))}
) : null} {!isLoading && personas.length > 0 ? ( -
- {personas.map((persona) => ( -
-
-
- -
-
-

- {persona.displayName} -

- {persona.isBuiltIn ? ( - - Built-in - - ) : null} +
+ {personas.map((persona) => { + const preview = promptPreview(persona.systemPrompt); + + return ( +
+
+
+ +
+
+

+ {persona.displayName} +

+ {persona.isBuiltIn ? ( + + Built-in + + ) : null} + {preview ? ( + + + + + +

{preview}

+
+
+ ) : null} +
-
- - - - - event.preventDefault()} - > - {!persona.isBuiltIn ? ( - onEdit(persona)} + + + + + event.preventDefault()} > - - Duplicate - - {!persona.isBuiltIn ? ( + {!persona.isBuiltIn ? ( + onEdit(persona)} + > + + Edit + + ) : null} onDelete(persona)} + onClick={() => onDuplicate(persona)} > - - Delete + + Duplicate - ) : null} - - + {!persona.isBuiltIn ? ( + onDelete(persona)} + > + + Delete + + ) : null} + + +
- -

- {promptPreview(persona.systemPrompt)} -

-
- ))} + ); + })}
) : null} diff --git a/desktop/src/features/tokens/lib/scopeOptions.ts b/desktop/src/features/tokens/lib/scopeOptions.ts index 838386c73a8..89dbd131977 100644 --- a/desktop/src/features/tokens/lib/scopeOptions.ts +++ b/desktop/src/features/tokens/lib/scopeOptions.ts @@ -3,19 +3,49 @@ import type { TokenScope } from "@/shared/api/types"; export const TOKEN_SCOPE_OPTIONS: Array<{ value: TokenScope; label: string; + description: string; }> = [ - { value: "messages:read", label: "Messages: Read" }, - { value: "messages:write", label: "Messages: Write" }, - { value: "channels:read", label: "Channels: Read" }, - { value: "channels:write", label: "Channels: Write" }, - { value: "users:read", label: "Users: Read" }, - { value: "files:read", label: "Files: Read" }, - { value: "files:write", label: "Files: Write" }, + { + value: "messages:read", + label: "Messages: Read", + description: "Read messages in joined channels", + }, + { + value: "messages:write", + label: "Messages: Write", + description: "Send messages and replies", + }, + { + value: "channels:read", + label: "Channels: Read", + description: "List and view channel metadata", + }, + { + value: "channels:write", + label: "Channels: Write", + description: "Create and update channels", + }, + { + value: "users:read", + label: "Users: Read", + description: "View user profiles and presence", + }, + { + value: "files:read", + label: "Files: Read", + description: "Download uploaded files", + }, + { + value: "files:write", + label: "Files: Write", + description: "Upload files to channels", + }, ]; export const MANAGED_AGENT_SCOPE_OPTIONS: Array<{ value: TokenScope; label: string; + description: string; }> = [...TOKEN_SCOPE_OPTIONS]; export const DEFAULT_MANAGED_AGENT_SCOPES: TokenScope[] = [