mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Hide non-invocable member agents from @-mention autocomplete (#1611)
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
getMentionableAgentPubkeys,
|
||||
getSharedChannelIds,
|
||||
relayAgentIsSharedWithUser,
|
||||
shouldHideAgentFromMentions,
|
||||
} from "./agentAutocompleteEligibility.ts";
|
||||
|
||||
const CURRENT_PUBKEY = "a".repeat(64);
|
||||
@@ -134,6 +135,87 @@ test("getMentionableAgentPubkeys: keeps managed agents and shared relay agents",
|
||||
assert.deepEqual(result, new Set([PUB_A, PUB_B, PUB_C]));
|
||||
});
|
||||
|
||||
test("shouldHideAgentFromMentions: never hides non-agents", () => {
|
||||
assert.equal(
|
||||
shouldHideAgentFromMentions({
|
||||
isAgent: false,
|
||||
isMember: false,
|
||||
pubkey: PUB_A,
|
||||
mentionableAgentPubkeys: new Set(),
|
||||
directoryAgentPubkeys: new Set([PUB_A]),
|
||||
}),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test("shouldHideAgentFromMentions: shows invocable agents even when non-member", () => {
|
||||
assert.equal(
|
||||
shouldHideAgentFromMentions({
|
||||
isAgent: true,
|
||||
isMember: false,
|
||||
pubkey: PUB_A,
|
||||
mentionableAgentPubkeys: new Set([PUB_A]),
|
||||
directoryAgentPubkeys: new Set([PUB_A]),
|
||||
}),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test("shouldHideAgentFromMentions: hides non-member non-invocable agents", () => {
|
||||
assert.equal(
|
||||
shouldHideAgentFromMentions({
|
||||
isAgent: true,
|
||||
isMember: false,
|
||||
pubkey: PUB_A,
|
||||
mentionableAgentPubkeys: new Set(),
|
||||
directoryAgentPubkeys: new Set(),
|
||||
}),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("shouldHideAgentFromMentions: hides member agents with an explicit not-invocable directory entry (Fizz)", () => {
|
||||
assert.equal(
|
||||
shouldHideAgentFromMentions({
|
||||
isAgent: true,
|
||||
isMember: true,
|
||||
pubkey: PUB_A,
|
||||
mentionableAgentPubkeys: new Set(),
|
||||
directoryAgentPubkeys: new Set([PUB_A]),
|
||||
}),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("shouldHideAgentFromMentions: shows member agents with unknown invocability (not in directory)", () => {
|
||||
assert.equal(
|
||||
shouldHideAgentFromMentions({
|
||||
isAgent: true,
|
||||
isMember: true,
|
||||
pubkey: PUB_A,
|
||||
mentionableAgentPubkeys: new Set(),
|
||||
directoryAgentPubkeys: new Set(),
|
||||
}),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test("shouldHideAgentFromMentions: normalizes the pubkey before lookup", () => {
|
||||
const mixedCase = "Ab".repeat(32);
|
||||
const normalized = mixedCase.toLowerCase();
|
||||
|
||||
assert.equal(
|
||||
shouldHideAgentFromMentions({
|
||||
isAgent: true,
|
||||
isMember: true,
|
||||
pubkey: mixedCase,
|
||||
mentionableAgentPubkeys: new Set(),
|
||||
directoryAgentPubkeys: new Set([normalized]),
|
||||
}),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test("coalesceAgentAutocompleteCandidates: merges agents with the same persona id", () => {
|
||||
const first = makeAgent({ pubkey: PUB_A, personaId: "pinky" });
|
||||
const second = makeAgent({
|
||||
|
||||
@@ -54,6 +54,39 @@ export function getMentionableAgentPubkeys({
|
||||
return pubkeys;
|
||||
}
|
||||
|
||||
export function shouldHideAgentFromMentions({
|
||||
isAgent,
|
||||
isMember,
|
||||
pubkey,
|
||||
mentionableAgentPubkeys,
|
||||
directoryAgentPubkeys,
|
||||
}: {
|
||||
isAgent: boolean;
|
||||
isMember: boolean;
|
||||
pubkey: string;
|
||||
mentionableAgentPubkeys: ReadonlySet<string>;
|
||||
directoryAgentPubkeys: ReadonlySet<string>;
|
||||
}) {
|
||||
if (!isAgent) return false;
|
||||
const normalized = normalizePubkey(pubkey);
|
||||
// Invocable => always show.
|
||||
if (mentionableAgentPubkeys.has(normalized)) return false;
|
||||
// Non-member, non-invocable => hide (preserves prior behavior).
|
||||
if (!isMember) return true;
|
||||
// Member (Option B): hide only when we have an explicit not-invocable
|
||||
// signal — a relay directory (kind:10100) entry that excludes us.
|
||||
// Unknown invocability (not in directory) => show.
|
||||
//
|
||||
// NOTE: this assumes `directoryAgentPubkeys` and `mentionableAgentPubkeys`
|
||||
// share the same source query (`relayAgentsQuery.data`), so directory
|
||||
// presence without membership in `mentionableAgentPubkeys` is a real
|
||||
// explicit-exclusion signal. If a future change sources the directory set
|
||||
// from a different query, an agent that's directory-present but whose
|
||||
// mentionability is still loading could be hidden prematurely — keep the
|
||||
// two sets derived from the same query.
|
||||
return directoryAgentPubkeys.has(normalized);
|
||||
}
|
||||
|
||||
type AgentAutocompleteCandidate = {
|
||||
pubkey?: string;
|
||||
displayName?: string | null;
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
coalesceAutocompleteCandidatesByKey,
|
||||
getMentionableAgentPubkeys,
|
||||
getSharedChannelIds,
|
||||
shouldHideAgentFromMentions,
|
||||
} from "@/features/agents/lib/agentAutocompleteEligibility";
|
||||
import {
|
||||
useInfiniteUserSearchQuery,
|
||||
@@ -209,6 +210,15 @@ export function useMentions(
|
||||
),
|
||||
[relayAgentsQuery.data],
|
||||
);
|
||||
const directoryAgentPubkeys = React.useMemo(
|
||||
() =>
|
||||
new Set(
|
||||
(relayAgentsQuery.data ?? []).map((agent) =>
|
||||
normalizePubkey(agent.pubkey),
|
||||
),
|
||||
),
|
||||
[relayAgentsQuery.data],
|
||||
);
|
||||
const sharedChannelIds = React.useMemo(
|
||||
() => getSharedChannelIds(channelsQuery.data),
|
||||
[channelsQuery.data],
|
||||
@@ -269,9 +279,13 @@ export function useMentions(
|
||||
return;
|
||||
}
|
||||
if (
|
||||
candidate.isAgent &&
|
||||
!candidate.isMember &&
|
||||
!mentionableAgentPubkeys.has(pubkey)
|
||||
shouldHideAgentFromMentions({
|
||||
isAgent: candidate.isAgent === true,
|
||||
isMember: candidate.isMember === true,
|
||||
pubkey,
|
||||
mentionableAgentPubkeys,
|
||||
directoryAgentPubkeys,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -425,6 +439,7 @@ export function useMentions(
|
||||
userSearchResults,
|
||||
canSearchGlobalUsers,
|
||||
currentPubkey,
|
||||
directoryAgentPubkeys,
|
||||
isArchivedDiscovery,
|
||||
managedAgentNamesByPubkey,
|
||||
managedAgentPersonaIds,
|
||||
|
||||
Reference in New Issue
Block a user