Skip to content

fix(desktop): shared relay agents are un-mentionable/un-addable — let directory eligibility run - #2605

Open
leesalminen wants to merge 1 commit into
block:mainfrom
leesalminen:fix/shared-relay-agents-mentionable
Open

fix(desktop): shared relay agents are un-mentionable/un-addable — let directory eligibility run#2605
leesalminen wants to merge 1 commit into
block:mainfrom
leesalminen:fix/shared-relay-agents-mentionable

Conversation

@leesalminen

Copy link
Copy Markdown
Contributor

Closes #2603

Summary

A shared relay agent (kind:0 + NIP-OA auth tag, kind:10100 directory profile with respond_to: anyone, channel member) responds fine when p-tagged, but nobody except its owning device can @-complete it or add it to channels: addCandidate in useMentions.ts drops every agent-flagged identity that isn't in the local managed-agents list before shouldHideAgentFromMentions runs, making the directory-eligibility path (mentionableAgentPubkeys, and the "Invocable => always show" / member Option-B rules) unreachable for foreign agents. MembersSidebar applies the same managed-list-only gate to add-member search.

Changes

  • useMentions.ts: remove the pre-emptive isAgentIdentityInManagedList gate. shouldHideAgentFromMentions is the single authority — it already shows invocable agents (local managed ∪ relay-directory-eligible), hides non-member non-invocable ones, and applies the member/directory rules. Local managed agents are unaffected (they're seeded into mentionableAgentPubkeys), and other members' owner-only agents stay hidden (non-member + non-invocable, or member + directory-excluded).
  • MembersSidebar.tsx: add-member candidates now pass when the agent is locally managed or relay-directory invocable by the current user (new relayAgentIsInvocableByUser: respond_to: anyone, or an allowlist containing them). Channel overlap is deliberately not required here — adding the agent to the channel is what creates the overlap.
  • agentAutocompleteEligibility.ts: new relayAgentIsInvocableByUser helper; relayAgentIsSharedWithUser delegates its allowlist branch to it (behavior unchanged); doc comment on isAgentIdentityInManagedList clarifying the caller-supplied allow-set contract.

Test plan

  • node --import ./test-loader.mjs --experimental-strip-types --test on agentAutocompleteEligibility.test.mjs: 22/22 (4 new: invocable-by-user modes, and a regression test that a directory-eligible member agent is shown without a local managed entry).
  • biome check and tsc --noEmit clean on touched files.
  • Manually verified against a self-hosted multi-tenant relay running a headless shared agent (buzz-acp + kind:10100, respond_to: anyone): with this fix the agent appears in mention autocomplete and add-member search on a desktop that does not manage it.

🤖 Generated with Claude Code

The composer's addCandidate dropped every agent-flagged identity not in
the LOCAL managed-agents list before shouldHideAgentFromMentions ran,
so the relay-directory eligibility path (kind:10100 RelayAgents with
respond_to anyone/allowlist and a shared channel) was dead code for
agents owned by other members. The members sidebar applied the same
managed-list-only gate to add-member search.

- useMentions: remove the pre-emptive gate; shouldHideAgentFromMentions
  is the single authority (it already shows invocable agents, hides
  non-member non-invocable ones, and applies the member/directory
  rules).
- MembersSidebar: gate add-candidates on managed agents plus relay
  agents that would respond to the current user, via the new
  relayAgentIsInvocableByUser helper. Channel overlap is deliberately
  not required there - adding the agent is what creates the overlap.
- relayAgentIsSharedWithUser now delegates its allowlist branch to the
  new helper; behavior unchanged.

Closes block#2603

Signed-off-by: Lee Salminen <[email protected]>
@leesalminen
leesalminen force-pushed the fix/shared-relay-agents-mentionable branch from c455107 to 0f1cc3a Compare July 25, 2026 15:19
@jonathanleiva15

Copy link
Copy Markdown

Confirming the root cause from another angle in case it's useful for the review.

Repro (mobile↔desktop parity): an externally-attested agent — one that joined a community via a NIP-OA owner auth tag (ViaOwner relay membership) and is a channel member — is mentionable in the mobile client but not in desktop, on the same account/relay. Mobile's buildMentionCandidates (mobile/lib/features/channels/mentions/mention_candidates.dart) adds all channel members unconditionally and only applies the invocability filter to non-members, so membership is sufficient there. On desktop, isAgentIdentityInManagedList (added in #2149) runs inside addCandidate before shouldHideAgentFromMentions and drops any isAgent && !managedAgentPubkeys.has(pk), so a member agent I don't locally manage never reaches the directory gate. Removing that pre-gate (this PR) restores the mobile semantics 👍

One sanity check for the review: #2149's stated intent was narrower than "managed-only" — de-duping owner-less stale p-tag copies of a persona I already manage (e.g. Bumble). Removing the gate entirely also lets owner-less member duplicates back in. If preserving that dedupe matters, a more surgical variant exempts only member + attested agents:

if (candidate.isAgent !== true) return true;
if (managedAgentPubkeys.has(normalizePubkey(candidate.pubkey))) return true;
return candidate.isMember === true && Boolean(candidate.ownerPubkey);

ownerPubkey is only set for a verified auth tag (profile_valid_oa_owner_pubkey in nostr_convert.rs), so it discriminates a legit external agent from a stale owner-less copy — and shouldHideAgentFromMentions still hides the "Fizz" (directory-excluded) case either way. Both approaches fix the reported symptom; just flagging the trade-off in case the owner-less dedupe was intentional. Happy to send a follow-up with tests if the surgical variant is preferred.

@Bartok9 Bartok9 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collaborative review (Bartok9)

Thanks @leesalminen — this is the cleanest desktop-only fix of the #2987 swarm I’ve looked at.

What’s strong

  1. Right authority: dropping the managed-list pre-gate in useMentions so shouldHideAgentFromMentions actually runs for external agents matches the diagnostic (#2987 report point 1).
  2. Add-member circularity fixed deliberately: relayAgentIsInvocableByUser (anyone/allowlist, no channel-overlap requirement) is the right split from relayAgentIsSharedWithUser for “invite path.”
  3. Tests of the regression: shouldHideAgentFromMentions: relay-shared agent shows without local managed entry + invocable helper cases — this is what reviewers need when five PRs claim the same one-line gate.
  4. Doc comment on isAgentIdentityInManagedList: renaming the mental model to caller-supplied allow-set is worth more than another prose PR body.

Suggestions (non-blocking unless maintainers want polish first)

  1. Owner self-mention edge (#3448’s isOwnAgent / respond_to: owner-only): with only relayAgentIsInvocableByUser, owner-only self agents on a remote host may still not mention/add themselves. Worth either:
    • a short “Out of scope / parented in #2987 footing / follow-up” note, or
    • a small additive own-pubkey escape aligned with 3448 if maintainers want one carrier for both.
  2. Name drift: helper is isAgentIdentityInManagedList but set is now “addable/mentionable.” A rename is optional and debatable (API churn); a one-line doc is already good.
  3. Call-site parity: only sidebar uses the expanded allow-set assembly; mentions relies on hide helper. That’s fine if getMentionableAgentPubkeys already unions managed ∪ invocable relay — a one-sentence call-path claim in the PR body would help maintainers grepping later (Brad-class: prove path, don’t just assert).

Swarm coordination (not a code nit)

Several open PRs touch the same gate (#3110, #3292, #2752, #3108, #3448, …). Prefer this + or #3448 as the merge vehicle so the thrash collapses. Happy to re-test a tip commit after rebase onto current main if useful.

Verdict: Approve-shape from a third-party collab angle — small, tested, correct layer. Not a maintainer formal approve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Desktop: shared relay agents owned by other members are un-mentionable and un-addable (managed-list gate precedes directory eligibility)

3 participants