import { useCallback } from "react"; import { useMutation, useQuery, useQueryClient, type QueryClient } from "@tanstack/react-query"; import { useSessionStore } from "@/stores/session-store"; export const ARCHIVE_AGENT_PENDING_QUERY_KEY = ["archive-agent-pending"] as const; export interface ArchiveAgentInput { serverId: string; agentId: string; } type ArchiveAgentPendingState = Record; interface SetAgentArchivingInput extends ArchiveAgentInput { queryClient: QueryClient; isArchiving: boolean; } interface IsAgentArchivingInput extends ArchiveAgentInput { queryClient: QueryClient; } interface AgentsListQueryData { entries?: Array<{ agent?: { id?: string | null } | null } | null>; } function toArchiveKey(input: ArchiveAgentInput): string { const serverId = input.serverId.trim(); const agentId = input.agentId.trim(); if (!serverId || !agentId) { return ""; } return `${serverId}:${agentId}`; } function readPendingState(queryClient: QueryClient): ArchiveAgentPendingState { return ( queryClient.getQueryData( ARCHIVE_AGENT_PENDING_QUERY_KEY ) ?? {} ); } function setAgentArchiving(input: SetAgentArchivingInput): void { const key = toArchiveKey(input); if (!key) { return; } input.queryClient.setQueryData( ARCHIVE_AGENT_PENDING_QUERY_KEY, (current) => { const state = current ?? {}; if (input.isArchiving) { if (state[key]) { return state; } return { ...state, [key]: true }; } if (!state[key]) { return state; } const next = { ...state }; delete next[key]; return next; } ); } function isAgentArchiving(input: IsAgentArchivingInput): boolean { const key = toArchiveKey(input); if (!key) { return false; } return Boolean(readPendingState(input.queryClient)[key]); } function removeAgentFromListPayload( payload: T, agentId: string ): T { if (!payload || !Array.isArray(payload.entries) || !agentId) { return payload; } const filtered = payload.entries.filter((entry) => entry?.agent?.id !== agentId); if (filtered.length === payload.entries.length) { return payload; } return { ...payload, entries: filtered, } as T; } function removeAgentFromCachedLists( queryClient: QueryClient, input: ArchiveAgentInput ): void { const agentId = input.agentId.trim(); if (!agentId) { return; } queryClient.setQueryData( ["sidebarAgentsList", input.serverId], (current) => removeAgentFromListPayload(current, agentId) ); queryClient.setQueryData( ["allAgents", input.serverId], (current) => removeAgentFromListPayload(current, agentId) ); } function markAgentArchivedInStore(input: ArchiveAgentInput & { archivedAt: string }): void { const archivedAt = new Date(input.archivedAt); if (Number.isNaN(archivedAt.getTime())) { return; } const setAgents = useSessionStore.getState().setAgents; setAgents(input.serverId, (prev) => { const existing = prev.get(input.agentId); if (!existing) { return prev; } if (existing.archivedAt && existing.archivedAt.getTime() === archivedAt.getTime()) { return prev; } const next = new Map(prev); next.set(input.agentId, { ...existing, archivedAt, }); return next; }); } export function clearArchiveAgentPending(input: IsAgentArchivingInput): void { setAgentArchiving({ ...input, isArchiving: false, }); } export function useArchiveAgent() { const queryClient = useQueryClient(); const pendingQuery = useQuery({ queryKey: ARCHIVE_AGENT_PENDING_QUERY_KEY, queryFn: async (): Promise => ({}), initialData: {} as ArchiveAgentPendingState, staleTime: Infinity, gcTime: Infinity, }); const archiveMutation = useMutation({ mutationFn: async (input: ArchiveAgentInput): Promise<{ archivedAt: string }> => { const client = useSessionStore.getState().sessions[input.serverId]?.client ?? null; if (!client) { throw new Error("Daemon client not available"); } return await client.archiveAgent(input.agentId); }, onMutate: (input) => { setAgentArchiving({ queryClient, serverId: input.serverId, agentId: input.agentId, isArchiving: true, }); }, onSuccess: (result, input) => { markAgentArchivedInStore({ serverId: input.serverId, agentId: input.agentId, archivedAt: result.archivedAt, }); removeAgentFromCachedLists(queryClient, input); void queryClient.invalidateQueries({ queryKey: ["sidebarAgentsList", input.serverId], }); void queryClient.invalidateQueries({ queryKey: ["allAgents", input.serverId], }); }, onSettled: (_result, _error, input) => { clearArchiveAgentPending({ queryClient, serverId: input.serverId, agentId: input.agentId, }); }, }); const archiveAgent = useCallback( async (input: ArchiveAgentInput): Promise => { if ( isAgentArchiving({ queryClient, serverId: input.serverId, agentId: input.agentId, }) ) { return; } await archiveMutation.mutateAsync(input); }, [archiveMutation, queryClient] ); const isArchivingAgent = useCallback( (input: ArchiveAgentInput): boolean => { const key = toArchiveKey(input); if (!key) { return false; } return Boolean((pendingQuery.data ?? {})[key]); }, [pendingQuery.data] ); return { archiveAgent, isArchivingAgent, }; } export const __private__ = { toArchiveKey, readPendingState, setAgentArchiving, isAgentArchiving, removeAgentFromListPayload, };