From f0b00672bfd726f71e4fa2229b037c2de3728698 Mon Sep 17 00:00:00 2001 From: iroiro147 Date: Sat, 1 Aug 2026 17:56:23 +0530 Subject: [PATCH] fix(mentions): coalesce persona definitions with running instances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #3947: The mention picker was showing persona-definition rows ('managed by you ยท not in channel') while omitting the actual running channel-member instances of those personas. Root cause: - Persona candidates were only filtered by managedAgentPersonaIds (personas linked to managed agent definitions) - Running instances with personaId set (from members or relayAgents) were not tracked or used for filtering - This caused orphaned persona definitions to appear while the actual running instances were omitted Fix: - Add instancePersonaIds to track personas that have running instances - Filter persona candidates to exclude personas with running instances - This ensures only persona definitions without any instance are shown as mintable candidates, while actual running instances are offered The mention picker now correctly shows running channel-member instances and excludes persona definitions that are already deployed as instances. Signed-off-by: iroiro147 --- .../src/features/messages/lib/useMentions.ts | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/desktop/src/features/messages/lib/useMentions.ts b/desktop/src/features/messages/lib/useMentions.ts index 0c73b75339..ec684d1d8d 100644 --- a/desktop/src/features/messages/lib/useMentions.ts +++ b/desktop/src/features/messages/lib/useMentions.ts @@ -233,6 +233,41 @@ export function useMentions( () => new Set(activePersonas.map((persona) => persona.id)), [activePersonas], ); + // Issue #3947: Also track persona IDs that have running instances (channel + // members or relay agents). Persona candidates should be filtered out when + // an instance exists for the same persona, so we only offer the actual + // running instance with a valid pubkey. + const instancePersonaIds = React.useMemo(() => { + const personaIds = new Set(); + for (const member of members ?? []) { + const pubkey = normalizePubkey(member.pubkey); + const personaId = + managedAgentPersonaIdsByPubkey.get(pubkey) ?? + (activePersonaById.has(pubkey) ? pubkey : undefined); + if (personaId) { + personaIds.add(personaId); + } + } + for (const agent of relayAgentsQuery.data ?? []) { + const pubkey = normalizePubkey(agent.pubkey); + const personaId = managedAgentPersonaIdsByPubkey.get(pubkey); + if (personaId) { + personaIds.add(personaId); + } + } + for (const agent of managedAgentsQuery.data ?? []) { + if (agent.personaId && agent.pubkey) { + personaIds.add(agent.personaId); + } + } + return personaIds; + }, [ + members, + relayAgentsQuery.data, + managedAgentsQuery.data, + managedAgentPersonaIdsByPubkey, + activePersonaById, + ]); const memberPubkeys = React.useMemo( () => new Set((members ?? []).map((member) => normalizePubkey(member.pubkey))), @@ -386,8 +421,15 @@ export function useMentions( } } + // Issue #3947: Filter out personas that have running instances. Only show + // persona definitions when there's no actual instance available (i.e., the + // persona hasn't been deployed yet). const personaCandidates: MentionCandidate[] = activePersonas - .filter((persona) => !managedAgentPersonaIds.has(persona.id)) + .filter( + (persona) => + !managedAgentPersonaIds.has(persona.id) && + !instancePersonaIds.has(persona.id), + ) .map((persona) => ({ kind: "persona" as const, personaId: persona.id, @@ -416,6 +458,7 @@ export function useMentions( canSearchGlobalUsers, currentPubkey, directoryAgentPubkeys, + instancePersonaIds, isArchivedDiscovery, managedAgentNamesByPubkey, managedAgentPersonaIds,