Skip to content

fix(agents): make agents mentionable by non-owners (desktop eligibility gate + kind:10100 directory) - #4713

Open
dexsynccom wants to merge 2 commits into
block:mainfrom
dexsynccom:fix/agent-mention-eligibility
Open

fix(agents): make agents mentionable by non-owners (desktop eligibility gate + kind:10100 directory)#4713
dexsynccom wants to merge 2 commits into
block:mainfrom
dexsynccom:fix/agent-mention-eligibility

Conversation

@dexsynccom

Copy link
Copy Markdown

Problem

On a multi-user deployment, only an agent's creator could interact with it from the desktop app. Other channel members typed @Agent … and got silence — the message posted normally, the relay accepted it, and the agent stayed healthy and kept answering its owner. The same members could reach the agent from the mobile app.

Root cause

Desktop mention p tags are only produced for identities present in the composer's mentionCandidates list — both the autocomplete picker and the send-time text matcher (extractMentionPubkeys) draw from it. isAgentIdentityInManagedList (#2149) drops every agent-flagged candidate not present in the local managed-agents list, and only the owner's machine has the agent there. Every feed into the candidate list flags such an agent (role == "bot" from kind:39002 membership; client-side NIP-OA owner verification on kind:0 for profile and search rows), so for non-owners the candidate is dropped on every path. Typing @Agent stays plain text, the event carries no p tag — and since the harness's Mentions mode subscribes with #p=[agent] in its REQ, the relay never even delivers the message to the agent. Nothing errors anywhere; mobile was unaffected because its member candidates have no such gate.

Compounding it, nothing anywhere published kind:10100 agent-directory profiles, so the respond_to-aware eligibility both clients already implement (relayAgentIsSharedWithUser / mobile agentIsSharedWithUser) had no data — respond_to=anyone was invisible to other users' clients.

Changes

fix(desktop): let non-owners @-mention channel-member agents

  • Scope isAgentIdentityInManagedList to agents owned by the current user (compared via the verified NIP-OA ownerPubkey), preserving fix(desktop): prefer live agent mentions #2149's stale-incarnation dedupe while letting foreign/unknown-owned agents fall through to shouldHideAgentFromMentions — whose member/directory policy applies again (member agents with unknown invocability are shown; non-member, non-invocable agents stay hidden).
  • Pass currentPubkey at both call sites (useMentions, MembersSidebar add-member search).
  • Move three pure helpers from useMentions.ts into mentionCandidates.ts to stay under the 1000-line file ratchet.
  • Unit tests for the owner-scoped semantics.

feat(acp): publish kind:10100 agent directory profile

  • New publish_agent_profile publishes/refreshes the replaceable kind:10100 at the presence-online readiness boundary and republishes when membership notifications change the subscribed channel set.
  • Content carries the cross-client contract fields — respond_to, respond_to_allowlist, channel_ids, channel_add_policy — already parsed by desktop agents_from_events, mobile AgentDirectoryEntry.fromEvent, and required by the relay's ingest side effect.
  • Discovery metadata only: the inbound author gate (author_allowed) remains the enforcement point.
  • Unit tests for the content contract, including the exact respond_to strings clients compare.

Testing

  • just ci green end-to-end (fmt, clippy, desktop check/build/unit tests, Tauri fmt/check/tests, mobile analyze/tests).
  • 672 unit tests across the touched desktop modules pass; 2 new harness tests pass.
  • Existing e2e mention-hiding semantics verified unchanged (mentions.spec.ts: foreign-owned non-member agents still hidden; own profile-only agents still hidden).
  • Root-caused on a live multi-user deployment: wire evidence (relay events/event_mentions) showed every non-owner message missing the agent p tag while the owner's carried it, with the same user succeeding from mobile and failing from desktop.

🤖 Generated with Claude Code

dexsynccom and others added 2 commits August 4, 2026 13:46
isAgentIdentityInManagedList (block#2149) dropped every agent-flagged mention
candidate not present in the local managed-agents list. Only the agent's
owner has it there, so for everyone else the candidate vanished from both
the autocomplete picker and the send-time p-tag extraction: typed
@mentions went out as plain text, the harness's require_mention #p
subscription never matched, and the agent silently ignored the message.
Members could reach agents from mobile (which has no such gate) but not
from desktop.

Scope the gate to what block#2149 actually wanted to hide — stale incarnations
of the current user's own agents — by comparing the candidate's verified
NIP-OA ownerPubkey with the current user. Foreign- or unknown-owned
agents now fall through to shouldHideAgentFromMentions, whose
member/directory policy applies again: member agents with unknown
invocability are shown; non-member, non-invocable agents stay hidden.

Moving formatSearchUserDisplayName, formatSearchUserSecondaryLabel and
appendUniqueName into mentionCandidates.ts keeps useMentions.ts under
the 1000-line ratchet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: dexsynccom <rifai@dexsync.com>
Clients already consume kind:10100 for mention eligibility (desktop
list_relay_agents, mobile agentDirectoryProvider) and the relay ingests
it with a users-table side effect, but nothing ever published it — so an
agent's respond_to/allowlist policy and channel set were invisible to
other users' clients, and respond_to=anyone had no effect on who could
see the agent in mention autocomplete.

Publish the profile at the presence-online readiness boundary and
republish whenever a membership notification changes the subscribed
channel set. Content carries the cross-client contract fields:
respond_to, respond_to_allowlist, channel_ids, channel_add_policy.
Discovery metadata only — the author gate (author_allowed) remains the
enforcement point.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: dexsynccom <rifai@dexsync.com>
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.

1 participant