feat(buzz-acp): publish the kind:10100 relay-agent directory entry - #6097
feat(buzz-acp): publish the kind:10100 relay-agent directory entry#6097Schnitzel wants to merge 1 commit into
Conversation
A harness-run agent cannot appear in Buzz Desktop's `@` autocomplete today, however healthy it is, and nothing reports why. Desktop builds its mentionable set as managed agents ∪ relay agents (`desktop/src/features/agents/knownAgentPubkeys.ts`). Managed agents are the ones the desktop holds a key for and runs itself, so an agent created in the app qualifies immediately and needs no relay event at all. An agent run by buzz-acp can never be in that set, which leaves the kind 10100 relay-agent directory entry as its only route — and buzz-acp never publishes one. `relayAgentCanRespondInChannel` then fails on an absent `channel_ids`, so the agent is silently offered nowhere. The failure is quiet at every layer: no error client-side, and a mention typed by hand goes out with no `p` tag, so it routes nowhere either. This publishes the entry from state the harness already has — the channels it discovered and subscribed to, plus its own author gate — at startup and again whenever a membership notification changes the channel set. Only subscribed channels are advertised, so the entry never offers a mention the agent would not receive. On membership change the channel set is re-read from the relay rather than trusted from local bookkeeping. Publishing is best-effort: discoverability is never worth failing a startup or dropping a membership update over, so failures are logged and execution continues. Kind 10100 is replaceable, so republishing supersedes rather than accumulating. Two flags, both opt-out/opt-in rather than changing existing behaviour for anyone who already publishes this entry themselves: --no-publish-directory / BUZZ_ACP_NO_PUBLISH_DIRECTORY --display-name / BUZZ_ACP_DISPLAY_NAME `name` is omitted when unset rather than guessed, so clients fall back to the agent's kind:0 profile name and then its npub, as they already do. `respond_to_allowlist` is emitted only in allowlist mode, mirroring the inbound author gate so the people who may prompt an agent are exactly the people whose client offers it. Tests cover the entry body: only subscribed channels are advertised, names stay positionally aligned with ids, the allowlist appears only in allowlist mode, blank names are omitted, and output is stable across builds so a replaceable event is not rewritten without cause. Signed-off-by: Michael Schmid <michael.schmid@amazee.com>
1cf0cbf to
203770b
Compare
…ry entry (block/buzz#6097) Buzz Desktop admits a non-owned agent to @-mention autocomplete only when the relay carries a kind:10100 directory entry for it (channel_ids + respond_to); nothing published one, so a hosted agent with respond_to=anyone was still mentionable by its owner alone. block/buzz#6097 has buzz-acp publish the entry at startup and on membership changes; the fork branch fountain-pin now carries it on top of #6088/#6101/#6103/#6104. #776's repin condition gains #6097. Refs #790.
…ry entry (block/buzz#6097) (#792) Buzz Desktop admits a non-owned agent to @-mention autocomplete only when the relay carries a kind:10100 directory entry for it (channel_ids + respond_to); nothing published one, so a hosted agent with respond_to=anyone was still mentionable by its owner alone. block/buzz#6097 has buzz-acp publish the entry at startup and on membership changes; the fork branch fountain-pin now carries it on top of #6088/#6101/#6103/#6104. #776's repin condition gains #6097. Refs #790.
The skill offered two routes onto a closed relay — NIP-AA virtual
membership or `buzz-admin add-member` — as a preference with one stated
cost, "a second thing to remember to revoke". They are not
interchangeable, and the difference is invisible until you go looking.
Virtual membership makes the relay resolve the agent's NIP-OA owner and
write users.agent_owner_pubkey. Enrolment does not: check_relay_membership
matches direct membership first and returns before the auth tag is read,
so a valid proof is discarded on every connection and no owner is ever
recorded. That column gates NIP-AO kind 24200 observer frames, so an
enrolled agent has every frame rejected and its ACP activity tab is empty
forever. Enrolling the agent is what breaks it.
Nothing reports this. The relay logs nothing and only increments
buzz_events_rejected_total{reason="auth"}, buzz-acp never surfaces the
OK=false, and the agent goes on reporting "relay observer enabled" with a
resolved owner. Sent upstream as block/buzz#6098.
The component table also claimed NIP-AO was "handled by buzz-acp", which
is wrong in the sense that matters: the frames are opt-in behind
--relay-observer and neither env example set it. So an agent built by
following this skill had no activity feed for two independent reasons.
Adds the flag to both env examples, a section on the two gates with the
query that tells them apart, the relay-side mechanism in internals, and
troubleshooting rows — including that a teammate seeing an empty tab is
correct, since the frames are encrypted to the owner alone.
Also notes block/buzz#6097 against the every-deploy 10100 republish: if
the harness carries that, the workaround stops being load-bearing.
|
Flagging honestly that #6338 has substantially reduced the value of this PR, in case that changes whether you want it. This publishes the kind 10100 directory entry from the harness, motivated mainly by the entry going stale: nothing republished it when the agent's channel set changed, so an agent added to a channel silently became unmentionable there. On our relay that bit four separate times in a week. In v0.5.18 the relay-agent directory no longer takes channels from the entry at all — agents.retain(|agent| member_agent_channel_ids.contains_key(&agent.pubkey));
for agent in &mut agents {
agent.channel_ids = member_agent_channel_ids.get(&agent.pubkey).cloned().unwrap_or_default();
}So the staleness problem this was written for is already solved, and better — membership now comes from the authority that owns it, rather than from a snapshot someone has to remember to refresh. On top of that, That leaves this PR useful only for agents with no owner-published 30177 — a shrinking set, given v0.5.18 also requires a verified NIP-OA owner. Happy to close it. I would only argue for keeping it if you want harness-run agents to be discoverable without owner-side provisioning, which is a product question rather than a bug. Your call — say the word and I will close, or I will rebase it if it is still wanted. (#6098 is unaffected by all this and still stands on its own — it is about the relay never recording |
The problem
An agent run by
buzz-acpnever appears in Buzz Desktop's@autocomplete, however healthy it is, and nothing anywhere reports why.Desktop builds its mentionable set as managed agents ∪ relay agents (
desktop/src/features/agents/knownAgentPubkeys.ts):relayAgentCanRespondInChannel— the entry'schannel_idsmust contain the channel being typed in, and itsrespond_tomust admit the person typing.A harness-run agent can never be in the first set, so kind 10100 is its only route.
buzz-acpnever publishes one.channel_idsis then absent,agents_from_eventsdefaults it to[], and the agent is eligible in no channel.The failure is silent end to end: no client-side error, and a mention typed by hand goes out with no
ptag, so it routes nowhere either. From the user's side a perfectly healthy bot simply cannot be mentioned.examples/countdown-bot's README attributes mentionability to therole=botself-add. In testing against a current relay and desktop that was not sufficient on its own; publishing kind 10100 was what made the agent appear.The change
Publishes the entry from state the harness already holds — the channels it discovered and subscribed to, plus its own author gate — at startup, and again whenever a membership notification changes the channel set.
Two new flags, so existing deployments that publish this entry themselves are unaffected:
--no-publish-directoryBUZZ_ACP_NO_PUBLISH_DIRECTORY--display-nameBUZZ_ACP_DISPLAY_NAMEnameis omitted when unset rather than guessed, so clients fall back to the agent's kind:0 profile name and then its npub, as they already do.respond_to_allowlistis emitted only in allowlist mode, mirroring the inbound author gate so the people who may prompt an agent are exactly the people whose client offers it.Testing
buzz-acpsuite: 783 passed, 0 failedcargo clippy -p buzz-acp --all-targetsclean,cargo fmtappliedQuestion for maintainers
Kind 10100 does not appear in any NIP under
docs/nips/, unlike the other agent-facing kinds (NIP-AP, NIP-AE, NIP-AO, NIP-AA). If it is intended to stay an internal convention I am happy to adjust; if it should be specified, I would be glad to draft it. Happy to change the default to opt-in if you would rather this not publish without being asked.