Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion desktop/src/features/channels/ui/ChannelPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,6 @@ export const ChannelPane = React.memo(function ChannelPane({
) : null}
<ComposerDockBackdrop gutterClassName="inset-x-5" />
<MessageComposer
audienceContext={{ type: "channel" }}
channelId={activeChannel?.id ?? null}
channelName={activeChannel?.name ?? "channel"}
channelType={activeChannel?.channelType ?? null}
Expand Down
13 changes: 12 additions & 1 deletion desktop/src/features/home/ui/InboxDetailPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,10 @@ function InboxMessageDetailPane({
: null;
const isThreadContext =
!isDirectMessage && hasInboxThreadContext(item, messages);
const threadRootTags = isThreadContext
? (displayMessages.find((message) => message.id === item.conversationId)
?.tags ?? [])
: [];
const contextLabel = isThreadContext
? isDirectMessage
? `Thread with ${item.senderLabel}`
Expand Down Expand Up @@ -804,7 +808,14 @@ function InboxMessageDetailPane({
/>
<div className="pointer-events-auto">
<MessageComposer
audienceContext={isDirectMessage ? null : { type: "thread" }}
audienceContext={
isDirectMessage
? null
: {
type: "thread",
rootTags: threadRootTags,
}
}
channelId={item.item.channelId}
channelName={item.channelLabel ?? "channel"}
channelType={composerChannelType}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,21 @@ test("explicitly excluded agents are not auto-promoted again", async () => {
assert.deepEqual(currentAudiences(store), { [scope]: [agentA] });
});

test("initialization preserves exclusions across thread remounts", async () => {
const store = await loadStore(14);
const scope = `${ownerA}:channel-a:thread-a`;

store.initializePersistentAgentAudience(scope, [agentA]);
assert.deepEqual(currentAudiences(store), { [scope]: [agentA] });

store.excludePersistentAgentAudienceMember(scope, agentA);
store.initializePersistentAgentAudience(scope, [agentA]);
assert.deepEqual(currentAudiences(store), { [scope]: [] });

store.addPersistentAgentAudienceMember(scope, agentA);
assert.deepEqual(currentAudiences(store), { [scope]: [agentA] });
});

test("explicit re-selection reinstates an excluded agent", async () => {
const store = await loadStore(13);
const scope = `${ownerA}:channel-a:channel`;
Expand Down
17 changes: 17 additions & 0 deletions desktop/src/features/messages/lib/persistentAgentAudience.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,23 @@ export function removePersistentAgentAudienceMembersIfUnchanged({
return true;
}

export function initializePersistentAgentAudience(
scope: string,
pubkeys: Iterable<string>,
): void {
if (!scope) return;
const excluded = excludedPubkeysByScope.get(scope);
const initialPubkeys = normalizePubkeys(pubkeys).filter(
(pubkey) =>
!(audiences[scope] ?? []).includes(pubkey) && !excluded?.has(pubkey),
);
if (initialPubkeys.length === 0) return;
setPersistentAgentAudience(scope, [
...(audiences[scope] ?? []),
...initialPubkeys,
]);
}

export function addPersistentAgentAudienceMember(
scope: string,
pubkey: string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ test("mention control expands with automatically mentioned agents", async () =>
const avatar = view.getByTestId("composer-address-lock-agent-pubkey");
assert.ok(avatar);
const manage = view.getByRole("button", {
name: "Manage automatic agent mentions",
name: "Manage mentions",
});
assert.match(manage.className, /(?:^|\s)-ml-2(?:\s|$)/);
assert.match(manage.className, /(?:^|\s)pl-2(?:\s|$)/);
Expand All @@ -82,18 +82,18 @@ test("mention control expands with automatically mentioned agents", async () =>
/(?:^|\s)pr-1\.5(?:\s|$)/,
);
assert.match(
view.getByRole("button", { name: "Manage automatic agent mentions" })
.parentElement?.className ?? "",
view.getByRole("button", { name: "Manage mentions" }).parentElement
?.className ?? "",
/(?:^|\s)bg-primary\/15(?:\s|$)/,
);
assert.match(
view.getByRole("button", { name: "Manage automatic agent mentions" })
.parentElement?.className ?? "",
view.getByRole("button", { name: "Manage mentions" }).parentElement
?.className ?? "",
/(?:^|\s)text-primary(?:\s|$)/,
);
assert.doesNotMatch(
view.getByRole("button", { name: "Manage automatic agent mentions" })
.parentElement?.className ?? "",
view.getByRole("button", { name: "Manage mentions" }).parentElement
?.className ?? "",
/(?:^|\s)bg-accent\/70(?:\s|$)/,
);
assert.doesNotMatch(
Expand All @@ -110,7 +110,13 @@ test("mention control expands with automatically mentioned agents", async () =>
/scale\(0.8\)/,
);
}
const remove = view.getByTestId("composer-address-lock-remove-agent-pubkey");
const remove = view.getByRole("button", {
name: "Don't automatically mention Agent Ada in this thread",
});
assert.equal(
remove.getAttribute("aria-label")?.includes("conversation"),
false,
);
const removeChrome = remove.querySelector("span.absolute");
assert.match(
removeChrome?.className ?? "",
Expand Down
14 changes: 4 additions & 10 deletions desktop/src/features/messages/ui/ComposerAddressControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,7 @@ export function ComposerMentionButton({
<Tooltip disableHoverableContent>
<TooltipTrigger asChild>
<button
aria-label={
hasAgents
? "Manage automatic agent mentions"
: "Mention someone"
}
aria-label={hasAgents ? "Manage mentions" : "Mention someone"}
className={cn(
"flex h-8 items-center justify-center rounded-lg focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
showActiveChrome
Expand All @@ -205,9 +201,7 @@ export function ComposerMentionButton({
</button>
</TooltipTrigger>
<TooltipContent>
{hasAgents
? "Manage automatic agent mentions"
: "Mention someone"}
{hasAgents ? "Manage mentions" : "Mention someone"}
</TooltipContent>
</Tooltip>
<AnimatePresence
Expand All @@ -234,7 +228,7 @@ export function ComposerMentionButton({
<Tooltip disableHoverableContent key={agent.pubkey}>
<TooltipTrigger asChild>
<motion.button
aria-label={`Don't automatically mention ${agent.displayName} in this conversation`}
aria-label={`Don't automatically mention ${agent.displayName} in this thread`}
animate={{ opacity: 1, scale: 1 }}
className="group/address relative rounded-full focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring"
data-testid={`composer-address-lock-remove-${agent.pubkey}`}
Expand Down Expand Up @@ -276,7 +270,7 @@ export function ComposerMentionButton({
</TooltipTrigger>
<TooltipContent>
Don't automatically mention {agent.displayName} in this
conversation
thread
</TooltipContent>
</Tooltip>
))}
Expand Down
Loading
Loading