diff --git a/desktop/src/features/agents/lib/agentAutocompleteEligibility.test.mjs b/desktop/src/features/agents/lib/agentAutocompleteEligibility.test.mjs index 4e02b7bd681..7778d30d8bd 100644 --- a/desktop/src/features/agents/lib/agentAutocompleteEligibility.test.mjs +++ b/desktop/src/features/agents/lib/agentAutocompleteEligibility.test.mjs @@ -7,6 +7,7 @@ import { getSharedChannelIds, isAgentIdentityInManagedList, relayAgentIsSharedWithUser, + shouldAdmitMentionCandidate, shouldHideAgentFromMentions, } from "./agentAutocompleteEligibility.ts"; @@ -136,7 +137,50 @@ test("getMentionableAgentPubkeys: keeps managed agents and shared relay agents", assert.deepEqual(result, new Set([PUB_A, PUB_B, PUB_C])); }); -test("isAgentIdentityInManagedList: keeps people and only current managed agent identities", () => { +test("shouldAdmitMentionCandidate: admits a cross-owner channel bot with anyone access", () => { + const mentionableAgentPubkeys = getMentionableAgentPubkeys({ + currentPubkey: CURRENT_PUBKEY, + managedAgentPubkeys: [], + relayAgents: [ + { + pubkey: PUB_B, + ownerPubkey: OTHER_OWNER_PUBKEY, + respondTo: "anyone", + respondToAllowlist: [], + channelIds: ["general"], + }, + ], + sharedChannelIds: new Set(["general"]), + }); + + assert.equal( + shouldAdmitMentionCandidate({ + isArchived: false, + isAgent: true, + isMember: true, + pubkey: PUB_B, + mentionableAgentPubkeys, + directoryAgentPubkeys: new Set([PUB_B]), + }), + true, + ); +}); + +test("shouldAdmitMentionCandidate: rejects archived identities", () => { + assert.equal( + shouldAdmitMentionCandidate({ + isArchived: true, + isAgent: false, + isMember: true, + pubkey: PUB_B, + mentionableAgentPubkeys: new Set(), + directoryAgentPubkeys: new Set(), + }), + false, + ); +}); + +test("isAgentIdentityInManagedList: scopes add-member search to managed agent identities", () => { const managedAgentPubkeys = new Set([PUB_A]); assert.equal( diff --git a/desktop/src/features/agents/lib/agentAutocompleteEligibility.ts b/desktop/src/features/agents/lib/agentAutocompleteEligibility.ts index e4afe7fea4a..0176e15b9c3 100644 --- a/desktop/src/features/agents/lib/agentAutocompleteEligibility.ts +++ b/desktop/src/features/agents/lib/agentAutocompleteEligibility.ts @@ -58,6 +58,8 @@ export function isAgentIdentityInManagedList( candidate: { isAgent?: boolean; pubkey: string }, managedAgentPubkeys: ReadonlySet, ) { + // This is an ownership filter for add-member search. Mention autocomplete + // uses the invocability policy in shouldAdmitMentionCandidate instead. return ( candidate.isAgent !== true || managedAgentPubkeys.has(normalizePubkey(candidate.pubkey)) @@ -97,6 +99,18 @@ export function shouldHideAgentFromMentions({ return directoryAgentPubkeys.has(normalized); } +export function shouldAdmitMentionCandidate(args: { + isArchived: boolean; + isAgent: boolean; + isMember: boolean; + pubkey: string; + mentionableAgentPubkeys: ReadonlySet; + directoryAgentPubkeys: ReadonlySet; +}) { + if (args.isArchived) return false; + return !shouldHideAgentFromMentions(args); +} + type AgentAutocompleteCandidate = { pubkey?: string; displayName?: string | null; diff --git a/desktop/src/features/messages/lib/useMentions.ts b/desktop/src/features/messages/lib/useMentions.ts index 0c73b753390..14a2dca54a7 100644 --- a/desktop/src/features/messages/lib/useMentions.ts +++ b/desktop/src/features/messages/lib/useMentions.ts @@ -16,8 +16,7 @@ import { coalesceAutocompleteCandidatesByKey, getMentionableAgentPubkeys, getSharedChannelIds, - isAgentIdentityInManagedList, - shouldHideAgentFromMentions, + shouldAdmitMentionCandidate, } from "@/features/agents/lib/agentAutocompleteEligibility"; import { useInfiniteUserSearchQuery, @@ -243,14 +242,9 @@ export function useMentions( const addCandidate = (candidate: MentionCandidate & { pubkey: string }) => { const pubkey = normalizePubkey(candidate.pubkey); - if (isArchivedDiscovery(pubkey)) { - return; - } - if (!isAgentIdentityInManagedList(candidate, managedAgentPubkeys)) { - return; - } if ( - shouldHideAgentFromMentions({ + !shouldAdmitMentionCandidate({ + isArchived: isArchivedDiscovery(pubkey), isAgent: candidate.isAgent === true, isMember: candidate.isMember === true, pubkey, @@ -420,7 +414,6 @@ export function useMentions( managedAgentNamesByPubkey, managedAgentPersonaIds, managedAgentPersonaIdsByPubkey, - managedAgentPubkeys, managedAgentsQuery.data, memberPubkeys, members,