mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(desktop): prefer live agent mentions (#2149)
Signed-off-by: npub1rf6fvdj6ut0c4kcmjv4p5mmgh89nj58n69uu3fz3cvk3jn500hqs7emz79 <1a7496365ae2df8adb1b932a1a6f68b9cb3950f3d179c8a451c32d194e8f7dc1@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub1rf6fvdj6ut0c4kcmjv4p5mmgh89nj58n69uu3fz3cvk3jn500hqs7emz79 <1a7496365ae2df8adb1b932a1a6f68b9cb3950f3d179c8a451c32d194e8f7dc1@sprout-oss.stage.blox.sqprod.co>
This commit is contained in:
co-authored by
npub1rf6fvdj6ut0c4kcmjv4p5mmgh89nj58n69uu3fz3cvk3jn500hqs7emz79
parent
9fb1a90b66
commit
a4dfead21a
@@ -5,6 +5,7 @@ import {
|
||||
coalesceAgentAutocompleteCandidates,
|
||||
getMentionableAgentPubkeys,
|
||||
getSharedChannelIds,
|
||||
isAgentIdentityInManagedList,
|
||||
relayAgentIsSharedWithUser,
|
||||
shouldHideAgentFromMentions,
|
||||
} from "./agentAutocompleteEligibility.ts";
|
||||
@@ -135,6 +136,32 @@ 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", () => {
|
||||
const managedAgentPubkeys = new Set([PUB_A]);
|
||||
|
||||
assert.equal(
|
||||
isAgentIdentityInManagedList(
|
||||
{ isAgent: false, pubkey: PUB_B },
|
||||
managedAgentPubkeys,
|
||||
),
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
isAgentIdentityInManagedList(
|
||||
{ isAgent: true, pubkey: PUB_A.toUpperCase() },
|
||||
managedAgentPubkeys,
|
||||
),
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
isAgentIdentityInManagedList(
|
||||
{ isAgent: true, pubkey: PUB_B },
|
||||
managedAgentPubkeys,
|
||||
),
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
test("shouldHideAgentFromMentions: never hides non-agents", () => {
|
||||
assert.equal(
|
||||
shouldHideAgentFromMentions({
|
||||
|
||||
@@ -54,6 +54,16 @@ export function getMentionableAgentPubkeys({
|
||||
return pubkeys;
|
||||
}
|
||||
|
||||
export function isAgentIdentityInManagedList(
|
||||
candidate: { isAgent?: boolean; pubkey: string },
|
||||
managedAgentPubkeys: ReadonlySet<string>,
|
||||
) {
|
||||
return (
|
||||
candidate.isAgent !== true ||
|
||||
managedAgentPubkeys.has(normalizePubkey(candidate.pubkey))
|
||||
);
|
||||
}
|
||||
|
||||
export function shouldHideAgentFromMentions({
|
||||
isAgent,
|
||||
isMember,
|
||||
|
||||
@@ -4,12 +4,10 @@ import { Bot, UserRoundPlus, X } from "lucide-react";
|
||||
import {
|
||||
useAddChannelMembersMutation,
|
||||
useChannelMembersQuery,
|
||||
useChannelsQuery,
|
||||
} from "@/features/channels/hooks";
|
||||
import {
|
||||
coalesceAgentAutocompleteCandidates,
|
||||
getMentionableAgentPubkeys,
|
||||
getSharedChannelIds,
|
||||
isAgentIdentityInManagedList,
|
||||
} from "@/features/agents/lib/agentAutocompleteEligibility";
|
||||
import { useIsArchivedPredicate } from "@/features/identity-archive/hooks";
|
||||
import { useClassifiedMembers } from "@/features/channels/lib/useClassifiedMembers";
|
||||
@@ -146,7 +144,6 @@ export function MembersSidebar({
|
||||
const identityQuery = useIdentityQuery();
|
||||
const membersQuery = useChannelMembersQuery(channelId, open);
|
||||
const addMembersMutation = useAddChannelMembersMutation(channelId);
|
||||
const channelsQuery = useChannelsQuery({ enabled: open });
|
||||
const changeRoleMutation = useMutation({
|
||||
mutationFn: async ({ pubkey, role }: { pubkey: string; role: string }) => {
|
||||
if (!channelId) throw new Error("No channel selected.");
|
||||
@@ -262,15 +259,7 @@ export function MembersSidebar({
|
||||
.map((member) => member.displayName?.trim().toLowerCase())
|
||||
.filter((label): label is string => Boolean(label)),
|
||||
);
|
||||
const sharedChannelIds = getSharedChannelIds(channelsQuery.data);
|
||||
const eligibleAgentPubkeys = getMentionableAgentPubkeys({
|
||||
currentPubkey,
|
||||
managedAgentPubkeys: (managedAgentsQuery.data ?? []).map(
|
||||
(agent) => agent.pubkey,
|
||||
),
|
||||
relayAgents: relayAgentsQuery.data,
|
||||
sharedChannelIds,
|
||||
});
|
||||
const managedAgentPubkeys = new Set(managedAgentsByPubkey.keys());
|
||||
|
||||
const addCandidate = (candidate: AddMemberSearchCandidate) => {
|
||||
const pubkey = normalizePubkey(candidate.pubkey);
|
||||
@@ -281,7 +270,7 @@ export function MembersSidebar({
|
||||
)) ||
|
||||
memberPubkeys.has(pubkey) ||
|
||||
isArchivedDiscovery(pubkey) ||
|
||||
(candidate.isAgent && !eligibleAgentPubkeys.has(pubkey))
|
||||
!isAgentIdentityInManagedList(candidate, managedAgentPubkeys)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -320,10 +309,6 @@ export function MembersSidebar({
|
||||
}
|
||||
|
||||
for (const agent of relayAgentsQuery.data ?? []) {
|
||||
if (!eligibleAgentPubkeys.has(normalizePubkey(agent.pubkey))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addCandidate({
|
||||
pubkey: agent.pubkey,
|
||||
displayName: agent.name,
|
||||
@@ -365,7 +350,6 @@ export function MembersSidebar({
|
||||
}, [
|
||||
canAddMembers,
|
||||
isArchivedDiscovery,
|
||||
channelsQuery.data,
|
||||
currentPubkey,
|
||||
managedAgentsQuery.data,
|
||||
memberPubkeys,
|
||||
@@ -377,8 +361,7 @@ export function MembersSidebar({
|
||||
const isAddSearchLoading =
|
||||
userSearchQuery.isLoading ||
|
||||
managedAgentsQuery.isLoading ||
|
||||
relayAgentsQuery.isLoading ||
|
||||
channelsQuery.isLoading;
|
||||
relayAgentsQuery.isLoading;
|
||||
const handlePeopleSearchScroll = useUserSearchFetchMoreOnScroll(
|
||||
userSearchQuery,
|
||||
canAddMembers && normalizedDeferredSearchQuery.length > 0,
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
coalesceAutocompleteCandidatesByKey,
|
||||
getMentionableAgentPubkeys,
|
||||
getSharedChannelIds,
|
||||
isAgentIdentityInManagedList,
|
||||
shouldHideAgentFromMentions,
|
||||
} from "@/features/agents/lib/agentAutocompleteEligibility";
|
||||
import {
|
||||
@@ -245,6 +246,9 @@ export function useMentions(
|
||||
if (isArchivedDiscovery(pubkey)) {
|
||||
return;
|
||||
}
|
||||
if (!isAgentIdentityInManagedList(candidate, managedAgentPubkeys)) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
shouldHideAgentFromMentions({
|
||||
isAgent: candidate.isAgent === true,
|
||||
@@ -256,7 +260,6 @@ export function useMentions(
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const current = candidatesByPubkey.get(pubkey);
|
||||
if (!current) {
|
||||
candidatesByPubkey.set(pubkey, { ...candidate, pubkey });
|
||||
@@ -289,7 +292,6 @@ export function useMentions(
|
||||
isManagedAgent: current.isManagedAgent || candidate.isManagedAgent,
|
||||
});
|
||||
};
|
||||
|
||||
for (const member of members ?? []) {
|
||||
const pubkey = normalizePubkey(member.pubkey);
|
||||
const linkedPersonaId = activePersonaById.has(pubkey)
|
||||
@@ -418,6 +420,7 @@ export function useMentions(
|
||||
managedAgentNamesByPubkey,
|
||||
managedAgentPersonaIds,
|
||||
managedAgentPersonaIdsByPubkey,
|
||||
managedAgentPubkeys,
|
||||
managedAgentsQuery.data,
|
||||
memberPubkeys,
|
||||
members,
|
||||
@@ -540,10 +543,7 @@ export function useMentions(
|
||||
mentionQuery,
|
||||
activePersonaIds,
|
||||
)
|
||||
.slice(
|
||||
0,
|
||||
Math.max(MENTION_SUGGESTION_LIMIT, mentionCandidatesWithTeams.length),
|
||||
)
|
||||
.slice(0, MENTION_SUGGESTION_LIMIT)
|
||||
.map(({ candidate, label }) =>
|
||||
mapMentionCandidateToSuggestion({
|
||||
candidate,
|
||||
|
||||
@@ -812,10 +812,17 @@ test("routes an agent mention from an existing DM to the expanded conversation",
|
||||
);
|
||||
});
|
||||
|
||||
test("routes a relay-agent mention from an existing DM to the expanded conversation", async ({
|
||||
test("routes a managed relay-agent mention from an existing DM to the expanded conversation", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey: DM_RELAY_AGENT_PUBKEY,
|
||||
name: "quinn",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
relayAgents: [
|
||||
{
|
||||
pubkey: DM_RELAY_AGENT_PUBKEY,
|
||||
@@ -856,15 +863,13 @@ test("routes a relay-agent mention from an existing DM to the expanded conversat
|
||||
page.locator("[data-active='true'][data-channel-id]"),
|
||||
).toHaveAttribute("data-channel-id", sentChannelId ?? "");
|
||||
await expect(page.getByTestId("chat-title")).toContainText("alice");
|
||||
await expect(page.getByTestId("chat-title")).toContainText(
|
||||
DM_RELAY_AGENT_PUBKEY.slice(0, 8),
|
||||
);
|
||||
await expect(page.getByTestId("chat-title")).toContainText("quinn");
|
||||
|
||||
const sendCommands = (await readCommandPayloadLog(page)).slice(
|
||||
baselineCommands.length,
|
||||
);
|
||||
expect(sendCommands.map((entry) => entry.command)).toContain("open_dm");
|
||||
expect(sendCommands.map((entry) => entry.command)).not.toContain(
|
||||
expect(sendCommands.map((entry) => entry.command)).toContain(
|
||||
"start_managed_agent",
|
||||
);
|
||||
expect(sendCommands.map((entry) => entry.command)).not.toContain(
|
||||
@@ -2554,7 +2559,18 @@ test("home inbox manage affordance opens management without leaving home", async
|
||||
await expect(page).not.toHaveURL(/#\/channels\//);
|
||||
});
|
||||
|
||||
test("members sidebar can invite and remove members", async ({ page }) => {
|
||||
test("members sidebar can invite and remove managed agents", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey: TEST_IDENTITIES.charlie.pubkey,
|
||||
name: "charlie",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
});
|
||||
await page.goto("/");
|
||||
await openMembersSidebar(page, "general");
|
||||
const initialMemberCount = await readMembersTriggerCount(page);
|
||||
@@ -2847,9 +2863,18 @@ test("members sidebar collapses same-persona managed agents", async ({
|
||||
await expect(page.getByText("Pinky", { exact: true })).toHaveCount(1);
|
||||
});
|
||||
|
||||
test("private-channel members can add members and bots without admin", async ({
|
||||
test("private-channel members can add people and managed agents without admin", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey: TEST_IDENTITIES.charlie.pubkey,
|
||||
name: "charlie",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
});
|
||||
await page.goto("/");
|
||||
// secret-projects is a private (non-DM) channel where the current user is a
|
||||
// plain member, not owner/admin. They should still be able to add members
|
||||
|
||||
@@ -166,38 +166,38 @@ test.describe("NIP-IA hide archived from discovery", () => {
|
||||
});
|
||||
|
||||
// Member-adder (ChannelMemberInviteCard) — the invite search excludes
|
||||
// existing channel members, so we test in #agents where Alice is NOT a
|
||||
// existing channel members, so we test in #agents where Bob is NOT a
|
||||
// member (only the mock identity + Charlie are): the ONLY thing that can
|
||||
// drop her from results is the archive filter. The control run (nothing
|
||||
// archived) proves she would otherwise appear — guarding a vacuous green.
|
||||
// drop Bob from results is the archive filter. The control run (nothing
|
||||
// archived) proves he would otherwise appear — guarding a vacuous green.
|
||||
test("member-adder: archived non-member is omitted from invite search", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, { archivedIdentities: [ALICE_PUBKEY] });
|
||||
await installMockBridge(page, { archivedIdentities: [BOB_PUBKEY] });
|
||||
await page.goto("/");
|
||||
await page.getByTestId("channel-agents").click();
|
||||
await page.getByTestId("channel-members-trigger").click();
|
||||
await expect(page.getByTestId("members-sidebar")).toBeVisible();
|
||||
await page.getByTestId("channel-management-search-users").fill("alice");
|
||||
await page.getByTestId("channel-management-search-users").fill("bob");
|
||||
await expect(
|
||||
page.getByTestId(`channel-user-search-result-${ALICE_PUBKEY}`),
|
||||
page.getByTestId(`channel-user-search-result-${BOB_PUBKEY}`),
|
||||
).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("member-adder: control — non-archived non-member IS in invite search", async ({
|
||||
page,
|
||||
}) => {
|
||||
// Same channel/query, nothing archived: Alice now appears. This is the
|
||||
// companion that makes the test above non-vacuous (proves she was dropped
|
||||
// Same channel/query, nothing archived: Bob now appears. This is the
|
||||
// companion that makes the test above non-vacuous (proves he was dropped
|
||||
// by the archive filter, not by member-exclusion or a broken search).
|
||||
await installMockBridge(page, { archivedIdentities: [] });
|
||||
await page.goto("/");
|
||||
await page.getByTestId("channel-agents").click();
|
||||
await page.getByTestId("channel-members-trigger").click();
|
||||
await expect(page.getByTestId("members-sidebar")).toBeVisible();
|
||||
await page.getByTestId("channel-management-search-users").fill("alice");
|
||||
await page.getByTestId("channel-management-search-users").fill("bob");
|
||||
await expect(
|
||||
page.getByTestId(`channel-user-search-result-${ALICE_PUBKEY}`),
|
||||
page.getByTestId(`channel-user-search-result-${BOB_PUBKEY}`),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -187,11 +187,18 @@ async function expectAgentProfileActionsHidden(
|
||||
).toHaveCount(0);
|
||||
}
|
||||
|
||||
test("@ trigger prioritizes channel members before runnable personas and other agents", async ({
|
||||
test("@ trigger prioritizes channel members before runnable personas and other managed agents", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, {
|
||||
activePersonaIds: ["builtin:fizz"],
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey: TEST_IDENTITIES.charlie.pubkey,
|
||||
name: "charlie",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
});
|
||||
await page.goto("/");
|
||||
await page.getByTestId("channel-general").click();
|
||||
@@ -202,7 +209,7 @@ test("@ trigger prioritizes channel members before runnable personas and other a
|
||||
|
||||
const dropdown = autocomplete(page);
|
||||
await expect(dropdown).toBeVisible();
|
||||
await expect(dropdown.getByText("alice")).toBeVisible();
|
||||
await expect(dropdown.getByText("alice")).toHaveCount(0);
|
||||
await expect(dropdown.getByText("bob")).toBeVisible();
|
||||
await expect(dropdown.getByText("Fizz")).toBeVisible();
|
||||
await expect(dropdown.getByText("charlie")).toBeVisible();
|
||||
@@ -219,7 +226,6 @@ test("@ trigger prioritizes channel members before runnable personas and other a
|
||||
const suggestions = dropdown.locator("button");
|
||||
const suggestionText = await suggestions.allInnerTexts();
|
||||
const fizzIndex = suggestionText.findIndex((text) => text.includes("Fizz"));
|
||||
const aliceIndex = suggestionText.findIndex((text) => text.includes("alice"));
|
||||
const bobIndex = suggestionText.findIndex((text) => text.includes("bob"));
|
||||
const charlieIndex = suggestionText.findIndex((text) =>
|
||||
text.includes("charlie"),
|
||||
@@ -228,11 +234,9 @@ test("@ trigger prioritizes channel members before runnable personas and other a
|
||||
text.includes("outsider"),
|
||||
);
|
||||
expect(fizzIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(aliceIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(bobIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(charlieIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(outsiderIndex).toEqual(-1);
|
||||
expect(aliceIndex).toBeLessThan(fizzIndex);
|
||||
expect(bobIndex).toBeLessThan(fizzIndex);
|
||||
expect(fizzIndex).toBeLessThan(charlieIndex);
|
||||
});
|
||||
@@ -425,7 +429,18 @@ test("defers agent mentions until DM members finish loading", async ({
|
||||
await expect(threadPanel).toContainText("before members resolve");
|
||||
});
|
||||
|
||||
test("autocomplete filters suggestions as user types", async ({ page }) => {
|
||||
test("autocomplete filters managed-agent suggestions as user types", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey: TEST_IDENTITIES.alice.pubkey,
|
||||
name: "alice",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
});
|
||||
await page.goto("/");
|
||||
await page.getByTestId("channel-general").click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
||||
@@ -462,7 +477,7 @@ test("autocomplete searches global non-member people from the first typed charac
|
||||
await expect(tessaRow.getByText("not in channel")).toBeVisible();
|
||||
});
|
||||
|
||||
test("mention autocomplete pages global people search beyond the first 50 results", async ({
|
||||
test("mention autocomplete caps global people search at 50 results", async ({
|
||||
page,
|
||||
}) => {
|
||||
const searchProfiles = Array.from({ length: 55 }, (_, index) => ({
|
||||
@@ -479,10 +494,8 @@ test("mention autocomplete pages global people search beyond the first 50 result
|
||||
|
||||
const dropdown = autocomplete(page);
|
||||
await expect(dropdown.locator("button")).toHaveCount(50);
|
||||
await dropdown.evaluate((node) => node.scrollTo(0, node.scrollHeight));
|
||||
|
||||
await expect(dropdown.locator("button")).toHaveCount(55);
|
||||
await expect(dropdown.getByText("Alex 55")).toBeVisible();
|
||||
await expect(dropdown.getByText("Alex 50")).toBeVisible();
|
||||
await expect(dropdown.getByText("Alex 55")).toHaveCount(0);
|
||||
await expect(dropdown.getByText("not in channel").last()).toBeVisible();
|
||||
|
||||
const searchCalls = (await readCommandPayloadLog(page)).filter(
|
||||
@@ -493,6 +506,10 @@ test("mention autocomplete pages global people search beyond the first 50 result
|
||||
expect.objectContaining({
|
||||
payload: expect.objectContaining({ cursor: null, limit: 50 }),
|
||||
}),
|
||||
]),
|
||||
);
|
||||
expect(searchCalls).not.toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
payload: expect.objectContaining({ cursor: "2", limit: 50 }),
|
||||
}),
|
||||
@@ -521,9 +538,18 @@ test("selecting a person mention inserts @Name into input", async ({
|
||||
await expect(mentionChip).not.toHaveClass(/agent-mention-highlight/);
|
||||
});
|
||||
|
||||
test("selecting an agent mention inserts @Name into input", async ({
|
||||
test("selecting a managed agent mention inserts @Name into input", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey: TEST_IDENTITIES.alice.pubkey,
|
||||
name: "alice",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
});
|
||||
await page.goto("/");
|
||||
await page.getByTestId("channel-general").click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
||||
@@ -691,9 +717,18 @@ test("selecting a persona mention reuses an existing persona agent", async ({
|
||||
await expect(mentionChip).toHaveText("Fizz");
|
||||
});
|
||||
|
||||
test("relay-profile agents with member roles use the agent composer style", async ({
|
||||
test("managed relay-profile agents with member roles use the agent composer style", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey: TEST_IDENTITIES.charlie.pubkey,
|
||||
name: "charlie",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
});
|
||||
await page.goto("/");
|
||||
|
||||
await openChannelBrowser(page);
|
||||
@@ -759,10 +794,17 @@ test("own profile-only agents are hidden from channel mentions", async ({
|
||||
await expect(autocomplete(page)).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("allowlisted relay agents are visible in channel mentions", async ({
|
||||
test("managed relay agents are visible in channel mentions regardless of relay policy", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey: ALLOWLIST_RELAY_AGENT_PUBKEY,
|
||||
name: "quinn",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
relayAgents: [
|
||||
{
|
||||
pubkey: ALLOWLIST_RELAY_AGENT_PUBKEY,
|
||||
@@ -784,7 +826,7 @@ test("allowlisted relay agents are visible in channel mentions", async ({
|
||||
await expect(dropdown.getByText("agent")).toBeVisible();
|
||||
});
|
||||
|
||||
test("non-allowlisted relay agents stay hidden from channel mentions", async ({
|
||||
test("relay-only agents stay hidden from channel mentions even when allowlisted", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, {
|
||||
@@ -793,7 +835,7 @@ test("non-allowlisted relay agents stay hidden from channel mentions", async ({
|
||||
pubkey: ALLOWLIST_RELAY_AGENT_PUBKEY,
|
||||
name: "quinn",
|
||||
respondTo: "allowlist",
|
||||
respondToAllowlist: [TEST_IDENTITIES.outsider.pubkey],
|
||||
respondToAllowlist: [MOCK_VIEWER_PUBKEY],
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1364,9 +1406,18 @@ test("system member-joined rows render the joined person as a plain profile name
|
||||
await expect(joinedPersonName).not.toHaveAttribute("data-mention");
|
||||
});
|
||||
|
||||
test("selecting a non-member agent from a DM inserts @Name into input", async ({
|
||||
test("selecting a managed non-member agent from a DM inserts @Name into input", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey: TEST_IDENTITIES.charlie.pubkey,
|
||||
name: "charlie",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
});
|
||||
await page.goto("/");
|
||||
await page.getByTestId("channel-bob-tyler").click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("bob-tyler");
|
||||
@@ -1450,9 +1501,18 @@ test("sent non-member person mention uses the normal mention style", async ({
|
||||
await expect(mentionChip.locator("svg")).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("sent non-member agent mention uses the agent mention style", async ({
|
||||
test("sent managed non-member agent mention uses the agent mention style", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey: TEST_IDENTITIES.charlie.pubkey,
|
||||
name: "charlie",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
});
|
||||
await page.goto("/");
|
||||
await page.getByTestId("channel-bob-tyler").click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("bob-tyler");
|
||||
|
||||
@@ -143,7 +143,16 @@ test("focus and split preserve reading context and interaction ownership", async
|
||||
await page.addInitScript(() => {
|
||||
localStorage.setItem("buzz.channels.threadViewMode", "focus");
|
||||
});
|
||||
await installMockBridge(page);
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey:
|
||||
"953d3363262e86b770419834c53d2446409db6d918a57f8f339d495d54ab001f",
|
||||
name: "alice",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
});
|
||||
await page.goto("/");
|
||||
const rootId = await seedLongThread(page);
|
||||
|
||||
|
||||
@@ -110,7 +110,16 @@ test.describe("list virtualization", () => {
|
||||
test("03 — members search shows both sticky titles under content-visibility", async ({
|
||||
page,
|
||||
}) => {
|
||||
await installMockBridge(page);
|
||||
await installMockBridge(page, {
|
||||
managedAgents: [
|
||||
{
|
||||
pubkey:
|
||||
"554cef57437abac34522ac2c9f0490d685b72c80478cf9f7ed6f9570ee8624ea",
|
||||
name: "charlie",
|
||||
status: "stopped",
|
||||
},
|
||||
],
|
||||
});
|
||||
await page.goto("/");
|
||||
await page.getByTestId("channel-general").click();
|
||||
await expect(page.getByTestId("chat-title")).toHaveText("general");
|
||||
|
||||
Reference in New Issue
Block a user