mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Delete persona-backed agents from profile
This commit is contained in:
@@ -28,11 +28,11 @@ export function PersonaDeleteDialog({
|
||||
<AlertDialog onOpenChange={onOpenChange} open={open}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Delete persona?</AlertDialogTitle>
|
||||
<AlertDialogTitle>Delete agent?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{persona
|
||||
? `Delete ${persona.displayName}. Existing agents keep their copied settings, but this template will no longer be available for new deployments.`
|
||||
: "Delete this persona."}
|
||||
? `Delete ${persona.displayName} and any managed instance tied to it. This cannot be undone.`
|
||||
: "Delete this agent."}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
|
||||
@@ -31,7 +31,6 @@ import { AddAgentToChannelDialog } from "@/features/agents/ui/AddAgentToChannelD
|
||||
import { useActiveAgentTurnsBridge } from "@/features/agents/activeAgentTurnsStore";
|
||||
import { resolvePersonaRuntime } from "@/features/agents/lib/resolvePersonaRuntime";
|
||||
import {
|
||||
deleteManagedAgentWithRules,
|
||||
isManagedAgentActive,
|
||||
startManagedAgentWithRules,
|
||||
stopManagedAgentWithRules,
|
||||
@@ -63,12 +62,12 @@ import {
|
||||
ModelFocusedView,
|
||||
ProfileSummaryView,
|
||||
} from "@/features/profile/ui/UserProfilePanelSections";
|
||||
import { useProfileAgentDeletion } from "@/features/profile/ui/UserProfilePanelDeletion";
|
||||
import { useProfileFieldBuckets } from "@/features/profile/ui/UserProfilePanelFields";
|
||||
import { UserProfilePersonaDialogs } from "@/features/profile/ui/UserProfilePersonaDialogs";
|
||||
import {
|
||||
buildPersonaDraftProfile,
|
||||
deriveProfileChannels,
|
||||
getRelayAgentChannelIds,
|
||||
PROFILE_PANEL_VIEW_TITLES,
|
||||
type ProfilePanelView,
|
||||
resolveAgentInstruction,
|
||||
@@ -82,7 +81,6 @@ import { useAgentSession } from "@/shared/context/AgentSessionContext";
|
||||
import { useEscapeKey } from "@/shared/hooks/useEscapeKey";
|
||||
import { useIsThreadPanelOverlay } from "@/shared/hooks/use-mobile";
|
||||
import { THREAD_PANEL_MIN_WIDTH_PX } from "@/shared/hooks/useThreadPanelWidth";
|
||||
import { removeChannelMember } from "@/shared/api/tauri";
|
||||
import {
|
||||
AuxiliaryPanelHeader,
|
||||
AuxiliaryPanelHeaderGroup,
|
||||
@@ -327,21 +325,18 @@ export function UserProfilePanel({
|
||||
setEditAgentOpen(true);
|
||||
}, [resolvedPersona]);
|
||||
|
||||
const removeAgentFromAllChannels = React.useCallback(
|
||||
async (agentPubkey: string) => {
|
||||
const channelIds = getRelayAgentChannelIds(
|
||||
relayAgentsQuery.data,
|
||||
agentPubkey,
|
||||
);
|
||||
if (channelIds.length === 0) return;
|
||||
await Promise.allSettled(
|
||||
channelIds.map((channelId) =>
|
||||
removeChannelMember(channelId, agentPubkey),
|
||||
),
|
||||
);
|
||||
},
|
||||
[relayAgentsQuery.data],
|
||||
);
|
||||
const {
|
||||
deleteManagedAgentRecord,
|
||||
deleteManagedAgentsForPersona,
|
||||
removeAgentFromAllChannels,
|
||||
} = useProfileAgentDeletion({
|
||||
channels: channelsQuery.data,
|
||||
deleteManagedAgent: deleteAgentMutation.mutateAsync,
|
||||
managedAgent,
|
||||
managedAgents: managedAgentsQuery.data,
|
||||
presenceLookup: presenceQuery.data,
|
||||
relayAgents: relayAgentsQuery.data,
|
||||
});
|
||||
|
||||
const handleAgentPrimaryAction = React.useCallback(async () => {
|
||||
if (!managedAgent) return;
|
||||
@@ -480,16 +475,9 @@ export function UserProfilePanel({
|
||||
if (!managedAgent) return;
|
||||
|
||||
try {
|
||||
const result = await deleteManagedAgentWithRules({
|
||||
agent: managedAgent,
|
||||
channels: channelsQuery.data ?? [],
|
||||
deleteManagedAgent: deleteAgentMutation.mutateAsync,
|
||||
presenceLookup: presenceQuery.data,
|
||||
relayAgents: relayAgentsQuery.data ?? [],
|
||||
});
|
||||
const result = await deleteManagedAgentRecord(managedAgent);
|
||||
if (result.cancelled) return;
|
||||
|
||||
await removeAgentFromAllChannels(managedAgent.pubkey);
|
||||
toast.success(`Deleted ${managedAgent.name}.`);
|
||||
onClose();
|
||||
} catch (error) {
|
||||
@@ -497,15 +485,7 @@ export function UserProfilePanel({
|
||||
error instanceof Error ? error.message : "Failed to delete agent.",
|
||||
);
|
||||
}
|
||||
}, [
|
||||
channelsQuery.data,
|
||||
deleteAgentMutation.mutateAsync,
|
||||
managedAgent,
|
||||
onClose,
|
||||
presenceQuery.data,
|
||||
relayAgentsQuery.data,
|
||||
removeAgentFromAllChannels,
|
||||
]);
|
||||
}, [deleteManagedAgentRecord, managedAgent, onClose]);
|
||||
|
||||
const handleSubmitPersona = React.useCallback(
|
||||
async (input: CreatePersonaInput | UpdatePersonaInput) => {
|
||||
@@ -563,6 +543,10 @@ export function UserProfilePanel({
|
||||
|
||||
if (resolvedPersona.isBuiltIn) {
|
||||
try {
|
||||
const deletedInstances =
|
||||
await deleteManagedAgentsForPersona(resolvedPersona);
|
||||
if (!deletedInstances) return;
|
||||
|
||||
await setPersonaActiveMutation.mutateAsync({
|
||||
id: resolvedPersona.id,
|
||||
active: false,
|
||||
@@ -583,11 +567,20 @@ export function UserProfilePanel({
|
||||
}
|
||||
|
||||
setPersonaToDelete(resolvedPersona);
|
||||
}, [onClose, resolvedPersona, setPersonaActiveMutation.mutateAsync]);
|
||||
}, [
|
||||
deleteManagedAgentsForPersona,
|
||||
onClose,
|
||||
resolvedPersona,
|
||||
setPersonaActiveMutation.mutateAsync,
|
||||
]);
|
||||
|
||||
const handleConfirmDeletePersona = React.useCallback(
|
||||
async (personaToConfirm: AgentPersona) => {
|
||||
try {
|
||||
const deletedInstances =
|
||||
await deleteManagedAgentsForPersona(personaToConfirm);
|
||||
if (!deletedInstances) return;
|
||||
|
||||
await deletePersonaMutation.mutateAsync(personaToConfirm.id);
|
||||
toast.success(`Deleted ${personaToConfirm.displayName}.`);
|
||||
setPersonaToDelete(null);
|
||||
@@ -598,7 +591,7 @@ export function UserProfilePanel({
|
||||
);
|
||||
}
|
||||
},
|
||||
[deletePersonaMutation.mutateAsync, onClose],
|
||||
[deleteManagedAgentsForPersona, deletePersonaMutation.mutateAsync, onClose],
|
||||
);
|
||||
|
||||
const handleAddedToChannel = React.useCallback(
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
import * as React from "react";
|
||||
|
||||
import {
|
||||
deleteManagedAgentWithRules,
|
||||
type ManagedAgentActionResult,
|
||||
} from "@/features/agents/lib/managedAgentControlActions";
|
||||
import { removeChannelMember } from "@/shared/api/tauri";
|
||||
import type {
|
||||
AgentPersona,
|
||||
Channel,
|
||||
ManagedAgent,
|
||||
PresenceLookup,
|
||||
RelayAgent,
|
||||
} from "@/shared/api/types";
|
||||
import { getRelayAgentChannelIds } from "@/features/profile/ui/UserProfilePanelUtils";
|
||||
|
||||
type DeleteManagedAgentRulesContext = Omit<
|
||||
Parameters<typeof deleteManagedAgentWithRules>[0],
|
||||
"agent"
|
||||
>;
|
||||
|
||||
type DeleteProfileManagedAgentContext = DeleteManagedAgentRulesContext & {
|
||||
removeAgentFromAllChannels: (pubkey: string) => Promise<void>;
|
||||
};
|
||||
|
||||
type DeleteProfileManagedAgentsForPersonaContext =
|
||||
DeleteProfileManagedAgentContext & {
|
||||
managedAgents: readonly ManagedAgent[];
|
||||
selectedAgent?: ManagedAgent;
|
||||
};
|
||||
|
||||
type UseProfileAgentDeletionInput = {
|
||||
channels?: readonly Channel[];
|
||||
deleteManagedAgent: DeleteManagedAgentRulesContext["deleteManagedAgent"];
|
||||
managedAgent?: ManagedAgent;
|
||||
managedAgents?: readonly ManagedAgent[];
|
||||
presenceLookup?: PresenceLookup | null;
|
||||
relayAgents?: readonly RelayAgent[];
|
||||
};
|
||||
|
||||
export function useProfileAgentDeletion({
|
||||
channels,
|
||||
deleteManagedAgent,
|
||||
managedAgent,
|
||||
managedAgents,
|
||||
presenceLookup,
|
||||
relayAgents,
|
||||
}: UseProfileAgentDeletionInput) {
|
||||
const removeAgentFromAllChannels = React.useCallback(
|
||||
async (agentPubkey: string) => {
|
||||
const channelIds = getRelayAgentChannelIds(relayAgents, agentPubkey);
|
||||
if (channelIds.length === 0) return;
|
||||
await Promise.allSettled(
|
||||
channelIds.map((channelId) =>
|
||||
removeChannelMember(channelId, agentPubkey),
|
||||
),
|
||||
);
|
||||
},
|
||||
[relayAgents],
|
||||
);
|
||||
|
||||
const deleteManagedAgentRecord = React.useCallback(
|
||||
(agentToDelete: ManagedAgent) =>
|
||||
deleteProfileManagedAgent(agentToDelete, {
|
||||
channels: channels ?? [],
|
||||
deleteManagedAgent,
|
||||
presenceLookup,
|
||||
relayAgents: relayAgents ?? [],
|
||||
removeAgentFromAllChannels,
|
||||
}),
|
||||
[
|
||||
channels,
|
||||
deleteManagedAgent,
|
||||
presenceLookup,
|
||||
relayAgents,
|
||||
removeAgentFromAllChannels,
|
||||
],
|
||||
);
|
||||
|
||||
const deleteManagedAgentsForPersona = React.useCallback(
|
||||
(persona: AgentPersona) =>
|
||||
deleteProfileManagedAgentsForPersona(persona, {
|
||||
channels: channels ?? [],
|
||||
deleteManagedAgent,
|
||||
managedAgents: managedAgents ?? [],
|
||||
presenceLookup,
|
||||
relayAgents: relayAgents ?? [],
|
||||
removeAgentFromAllChannels,
|
||||
selectedAgent: managedAgent,
|
||||
}),
|
||||
[
|
||||
channels,
|
||||
deleteManagedAgent,
|
||||
managedAgent,
|
||||
managedAgents,
|
||||
presenceLookup,
|
||||
relayAgents,
|
||||
removeAgentFromAllChannels,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
deleteManagedAgentRecord,
|
||||
deleteManagedAgentsForPersona,
|
||||
removeAgentFromAllChannels,
|
||||
};
|
||||
}
|
||||
|
||||
export async function deleteProfileManagedAgent(
|
||||
agent: ManagedAgent,
|
||||
context: DeleteProfileManagedAgentContext,
|
||||
): Promise<ManagedAgentActionResult> {
|
||||
const { removeAgentFromAllChannels, ...deleteContext } = context;
|
||||
const result = await deleteManagedAgentWithRules({
|
||||
agent,
|
||||
...deleteContext,
|
||||
});
|
||||
if (result.cancelled) return result;
|
||||
|
||||
await removeAgentFromAllChannels(agent.pubkey);
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function deleteProfileManagedAgentsForPersona(
|
||||
persona: AgentPersona,
|
||||
context: DeleteProfileManagedAgentsForPersonaContext,
|
||||
): Promise<ManagedAgentActionResult> {
|
||||
const { managedAgents, selectedAgent, ...deleteContext } = context;
|
||||
const agentsByPubkey = new Map<string, ManagedAgent>();
|
||||
|
||||
for (const agent of managedAgents) {
|
||||
if (agent.personaId === persona.id) {
|
||||
agentsByPubkey.set(agent.pubkey, agent);
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedAgent?.personaId === persona.id) {
|
||||
agentsByPubkey.set(selectedAgent.pubkey, selectedAgent);
|
||||
}
|
||||
|
||||
for (const agent of agentsByPubkey.values()) {
|
||||
const result = await deleteProfileManagedAgent(agent, deleteContext);
|
||||
if (result.cancelled) return result;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -321,7 +321,7 @@ export function ProfileSummaryView({
|
||||
<UserProfileAgentActions
|
||||
isPending={isAgentActionPending}
|
||||
managedAgent={managedAgent}
|
||||
onDelete={handleDeleteAgent}
|
||||
onDelete={persona ? handleDeletePersona : handleDeleteAgent}
|
||||
onDuplicatePersona={handleDuplicatePersona}
|
||||
onExportPersona={handleExportPersona}
|
||||
personaActionKey={personaActionKey}
|
||||
|
||||
Reference in New Issue
Block a user