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
-
-
-
- Refresh
-
-
+
+
+
+
+
+
+ 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
-
-
-
- Refresh
-
-
+
+
+
+
+
+
+ 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)}
+
+
+
-
- Edit
-
- ) : null}
- onDuplicate(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[] = [