Skip to content

fix(acp): accept owner control commands with rendered mention text - #7816

Open
madmada wants to merge 5 commits into
block:mainfrom
madmada:fix/acp-control-command-mention-text
Open

madmada wants to merge 5 commits into
block:mainfrom
madmada:fix/acp-control-command-mention-text

Conversation

@madmada

@madmada madmada commented Sep 22, 2026

Copy link
Copy Markdown

Summary

This is #6101 by @jhgaylor rebased onto current main. #6101 no longer merges cleanly: main has since reworked the same area of lib.rs (#6129 and its revert #6311) and the README (thread-scoped sessions, #6732). The fix and the test are his, and so is the commit authorship. I resolved the conflicts, added tests, updated two docs and ran it end to end against a local relay:

  • crates/buzz-acp/src/lib.rs: kept control_command_content_matches and its test unchanged. Dropped workflow_attributed_author, which only came along as conflict context. It was removed from main in Revert "fix(acp): gate relay-signed workflow messages on their attributed author" #6311.
  • New test owner_control_command_gate_accepts_rendered_mention_for_every_command (separate commit). buzz-acp: accept owner control commands with rendered mention text #6101's test covers the helper only. This one asserts on is_owner_control_command for !shutdown, !cancel and !rotate, so reverting the gate to an exact-content check fails it (checked). It also rejects a p tag for another agent and a missing p tag. A second commit adds the two other label shapes Desktop produces to the matcher table: @Name (<pubkey>) !rotate (Desktop qualifies a label this way when two selected mentions share a display name) and @Agent @Other Agent !rotate.
  • docs/welcome-kickoff-silent-failures.md: buzz-acp: accept owner control commands with rendered mention text #6101 prefixed a "Fixed" note to the backlog item but left its diagnosis in present tense. Rewrote it as resolved and kept the still-current "!cancel is not a loop breaker" note (separate commit).
  • desktop/src/features/agents/AGENTS.md: the "Channel-only runtime controls" section told contributors not to suggest @Agent !cancel, because the harness required the exact body. It now says the owner can reply in the target thread with @Agent !cancel or !rotate, and keeps the CLI example.
  • crates/buzz-acp/README.md: replaced the "body must be exactly !rotate … an inline @Name does not match" paragraph with buzz-acp: accept owner control commands with rendered mention text #6101's mention-tolerant wording. Kept the CLI --reply-to … --mention … --content '!cancel' example from main, since a bare command with a separate p tag still matches and is the way to target a thread from the CLI.

Behaviour (unchanged from #6101): @Agent !rotate, !rotate @Agent and nostr:npub… !rotate from the owner, with the agent's p tag, are consumed as control commands. Because the harness does not know the agent's rendered (possibly multi-word) display name, any prefix starting with @ or nostr: counts as mention text, so @Agent please !rotate also matches. Content that does not start with a mention or continues past the command (please !rotate, !rotate now) is still forwarded as an ordinary message. The owner, p-tag and kind:9 checks are untouched. Under the thread session policy the command still resolves to the thread it is posted in.

@jhgaylor, if you would rather rebase #6101 yourself, say so and I'll close this.

Related issue

Fixes #6014, fixes #6051. Supersedes #6101.

Testing

  • cargo test -p buzz-acp: lib 943 passed, integration 9 passed, 0 failed (run with no BUZZ_ACP_* variables in the environment, because two config::tests default assertions read them)

  • cargo fmt -p buzz-acp -- --check, cargo clippy -p buzz-acp --all-targets -- -D warnings

  • End to end: local relay (scripts/start-isolated-test-relay.sh stack), buzz-acp built from this branch and from main (77729ab), and a stub ACP agent that logs every session/new and session/prompt. Test events were published with the shape Desktop produces (content @Mock Agent !rotate, tags h, p, ["mention", <agent>, "agent-address"], and ["e", <root>, "", "reply"] for thread replies). They were not typed in the Desktop UI.

    Step main this branch
    Owner, idle: @Mock Agent !rotate, then a message forwarded to the agent as a prompt, same session consumed, not forwarded; next message opens a new session
    Owner, mid-turn: @Mock Agent !rotate forwarded (steers the running turn) session/cancel for the running turn; next message opens a new session
    Owner: @Mock Agent !cancel mid-turn forwarded session/cancel, the turn stops
    Non-owner: @Mock Agent !rotate forwarded forwarded, no rotate
    Owner: @Mock Agent !rotate now forwarded forwarded, no rotate
    Owner: bare !rotate with p tag rotates rotates
    thread policy: @Mock Agent !rotate replied in thread A forwarded into thread A's session thread A gets a new session; thread B keeps its session

    Unchanged from main, for reviewers: a turn cancelled by any control signal (including !cancel and Desktop's Stop) invalidates the session, so the next message after !cancel also opens a new session.

This PR was prepared with an AI coding agent. I reviewed the change and take responsibility for it.

🤖 Generated with Claude Code

jhgaylor and others added 5 commits September 22, 2026 16:15
Desktop and mobile insert a mention into the message body as literal text
("@Fountain Maintainer !rotate") alongside the p tag, but
is_owner_control_command required content.trim() to equal the command
exactly. So a mentioned command fell through to the agent as a prompt, and
a bare command had no p tag and was dropped — the commands were unreachable
from every product surface (already noted in
docs/welcome-kickoff-silent-failures.md §5).

Match the command when it is the whole content, or when it is the last or
first token with only @name / nostr: mention text on the other side. Content
that continues past the command is still forwarded as an ordinary message.

[Adam Pałka: rebased block#6101 onto main; dropped workflow_attributed_author
(removed on main by block#6311) from the lib.rs conflict and merged the README
paragraph with the thread-scope CLI example added on main.]

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Jake Gaylor <jhgaylor@gmail.com>
Signed-off-by: Adam Pałka <adm.palka@gmail.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
The matcher test from the previous commit exercises the helper only, so
reverting is_owner_control_command to an exact-content check would still
pass. Assert on is_owner_control_command itself for !shutdown, !cancel and
!rotate with rendered mention text, and reject events whose p tag names
another agent or is missing.

Signed-off-by: Adam Pałka <adm.palka@gmail.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
The previous commit only prefixed a "Fixed" note, leaving the diagnosis in
present tense. Rewrite the entry as resolved and keep the still-current
loop-breaker limitation.

Signed-off-by: Adam Pałka <adm.palka@gmail.com>
Co-authored-by: Claude Code <noreply@anthropic.com>
Desktop qualifies a mention label with the pubkey when two selected
mentions share a display name, and one message can address several
agents. Both shapes must still match as control commands.

Co-authored-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Adam Pałka <adm.palka@gmail.com>
The harness now accepts owner control commands whose body carries the
rendered mention text, so the composer is a working per-thread
fallback until observer controls become thread-aware.

Co-authored-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Adam Pałka <adm.palka@gmail.com>
@madmada
madmada requested a review from a team as a code owner September 22, 2026 22:00
@github-actions

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 26ede6dfa2496993aa62ce5781d2112df4c2d009...c8a63de004ae85ea718e95206697e4e2b33441e6.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review c8a63de004ae85ea718e95206697e4e2b33441e6 to authorize a new review.
Any previous review applies only to its recorded range.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

2 participants