Skip to content

Desktop: agents owned by another user are never mentionable — managed-list guard in useMentions dead-codes shouldHideAgentFromMentions #3671

Description

@NachoG2000

Desktop: agents owned by another user are never mentionable — the managed-list guard in useMentions dead-codes shouldHideAgentFromMentions

Summary

On Buzz Desktop, an agent deployed by user A is invisible in user B's @-mention autocomplete — even when the agent is a member of the same channel and B is on the agent's respond_to allowlist. Typing the name by hand doesn't help either: the message is sent without a p tag, so the agent's harness never triggers.

This makes cross-user agent collaboration (the "agents are members, not bots" story from the README) work on mobile but not on desktop.

Root cause

In desktop/src/features/messages/lib/useMentions.ts, addCandidate runs two gates in sequence:

if (!isAgentIdentityInManagedList(candidate, managedAgentPubkeys)) return;   // gate 1
if (shouldHideAgentFromMentions({ ..., mentionableAgentPubkeys, ... })) return; // gate 2
  1. Gate 1 drops every isAgent candidate whose pubkey is not in the local managed-agent list (managed-agents.json). On any install that doesn't manage agents itself, this is the empty set — every agent candidate dies here, including channel members with role bot.
  2. Gate 2 (shouldHideAgentFromMentions) starts with if (mentionableAgentPubkeys.has(normalized)) return false; // Invocable => always show.
  3. getMentionableAgentPubkeys seeds its result with managedAgentPubkeys (agentAutocompleteEligibility.ts), so managedAgentPubkeys ⊆ mentionableAgentPubkeys always holds.

⟹ Every agent candidate that survives gate 1 is already "invocable" to gate 2, which therefore returns false on its first line, always. All remaining branches of shouldHideAgentFromMentions — including the "Option B" member branch (lines 84–97) whose comment block explicitly specifies "Member: … Unknown invocability (not in directory) => show" — are unreachable from their only production call site. The policy documented there was designed for exactly this scenario, and gate 1 starves it.

Evidence this is a regression, not intent

  • The mobile client is the witness. mobile/lib/features/channels/mentions/mention_candidates.dart implements the same pipeline without the pre-gate (member bots are always candidates; agentIsSharedWithUser handles non-member directory agents), and its comments say "Mirrors desktop's shouldHideAgentFromMentions". The port codified desktop's intended semantics; desktop no longer executes them.
  • Coverage has a hole exactly here. The e2e suite pins "relay-only (non-member) agents stay hidden" and "own managed agents are visible" — there is no test for channel-member agent owned by another user.
  • The typed-mention fallback is also starved. extractMentionPubkeys has an explicit loop resolving hand-typed @Name against channel members without autocomplete. It works for humans; for foreign agents, gate 1 has already removed them from mentionCandidates.

Net effect: on a desktop with an empty managed list, no agent is mentionable at all — not even one with respond_to: anyone. The client-side allowlist/anyone logic (relayAgentIsSharedWithUser, getMentionableAgentPubkeys) is unreachable ornament.

isAgentIdentityInManagedList has a legitimate job — its unit test says "keeps people and only current managed agent identities", i.e. dropping stale/ghost agent identities surfaced by discovery/search. The bug is only that it also swallows relay-confirmed channel members.

Fix

Exempt channel members from gate 1 so that gate 2 — which already encodes the correct member policy — actually decides:

if (
  candidate.isMember !== true &&
  !isAgentIdentityInManagedList(candidate, managedAgentPubkeys)
) {
  return;
}

Ghost-guard semantics are preserved for non-members (discovery, directory, global search), so the pinned "relay-only agents stay hidden" behavior is unchanged.

PR with the fix and an e2e regression test (channel-member bot + empty managed list ⇒ visible in @, mention resolves to a p tag on the wire): #TBD

Repro

  1. User A deploys an agent and adds it to a shared channel (member role bot).
  2. User B (no locally managed agents) opens the channel on desktop and types @.
  3. The agent is missing from the list; typing @AgentName by hand sends a message without any p tag (verifiable in the event), so the agent never responds.
  4. Same account, same channel on mobile: the agent appears and the mention works.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions