Skip to content

fix(buzz-acp): anchor human-facing thread replies to the triggering message - #4092

Open
iroiro147 wants to merge 2 commits into
block:mainfrom
iroiro147:claude/issue4072-trigger-anchor-20260801
Open

fix(buzz-acp): anchor human-facing thread replies to the triggering message#4092
iroiro147 wants to merge 2 commits into
block:mainfrom
iroiro147:claude/issue4072-trigger-anchor-20260801

Conversation

@iroiro147

Copy link
Copy Markdown

Problem

When a human is already talking with an agent inside a thread, the agent's reply previously flattened to the thread root regardless of which message in the thread actually triggered the turn. With multiple messages in flight, the reader could not tell which message the agent was answering, and the agent felt less proactive (#4072).

DM turns already anchored to the exact triggering message; the non-DM thread branch was the inconsistent one.

Fix

resolve_reply_anchor() now returns triggering_event_id in every human-facing case:

Case Before After
In a thread thread root triggering event id
Top-level triggering event id triggering event id (same)
Agent↔agent None (deep nest) None (unchanged)

The --reply-to hint now points at the exact message that triggered the turn, so the UI renders the agent's reply directly under the message being answered, preserving the author mention for that parent.

The escape hatch is preserved: the hints text still says agents may honor an explicit "post in channel root" user request by omitting --reply-to, and agent↔agent turns still get no forced anchor so coordination turns stay deeply nested.

Tests

  • Regression (inverted): test_human_thread_reply_anchors_to_root_not_triggering_or_parent…to_triggering_event_not_root_or_parent (asserts anchor=triggering event, NOT root, NOT intermediate parent).
  • New depth≥2 regression: test_anchor_human_nested_reply_in_dm and the comment above the is_dm branch were already there; now anchor=TRIGGER_ID (was ROOT_ID).
  • test_reply_instruction_present_for_channel_thread_reply — now asserts --reply-to <triggering event id> instead of <root id>, plus explicit NOT-root assertion.
  • test_reply_instruction_allows_explicit_root_post_requests — anchor assertion switched to triggering id; explicit-root escape-hatch text assertion preserved unchanged.
  • test_reply_instruction_batched_last_event_is_threaded — asserts anchor is the batched last event's own id.
  • test_steer_cross_thread_reply_targets_steering_message — asserts anchor is the steering message id (not its thread root), matching the new human-facing supersede semantics.

Verification

cargo test   -p buzz-acp --lib                          # 663 passed, 0 failed
cargo clippy -p buzz-acp --all-targets -- -D warnings   # clean

Fixes #4072.

In All mode with no BUZZ_ACP_KINDS override, the ACP harness subscribed
with a true wildcard (kinds: None). Any sibling agents sharing a channel
then woke on each other's bookkeeping traffic — kind 7 (reactions,
including the harness's own 👀/💬 lifecycle markers) and kind 5
(NIP-09 deletions) — and stormed on each other's wake events, burning
tokens and flooding the channel with turns nobody asked for.

When kinds_override is None, both resolve_channel_filters() and
resolve_dynamic_channel_filter() now install the same curated default
kind list:

    [9, 40002, 40003, 1059, 40007, 40100, 46010, 46020]

i.e. stream chat (v1/v2/edit), gift-wrapped DMs, stream reminders,
canvas, workflow approval requests, and workflow triggers — every kind
an agent legitimately needs to wake on. Kinds 5 (NIP-09 deletion) and
7 (reaction) are excluded: they are harness bookkeeping, not user
intent.

Users who genuinely want the old wildcard can still set
BUZZ_ACP_KINDS explicitly including 5 and 7; the override remains
authoritative.

Tests updated:
- test_all_mode_wildcard now asserts the curated list (and asserts it
  excludes kinds 5 and 7).
- New test_all_mode_dynamic_channel_matches_static locks the dynamic
  (instant-join) resolver to the same defaults as the bootstrap
  resolver, so instantly-joined channels behave identically to
  bootstrapped ones.
- test_all_mode_with_kinds_override still passes unchanged.

Fixes block#4086.

Signed-off-by: Sarthak Singh <sarthak.singh@juspay.in>
…essage

When a human talks with an agent inside a thread, the agent's reply
previously flattened to the thread root, so a reply to a depth-2 nested
question looked identical to a reply to the thread head. With multiple
messages in flight the reader could not tell which message the agent
was answering, and the agent felt less proactive. (block#4072)

Change resolve_reply_anchor() to return triggering_event_id in every
human-facing case (thread or top-level). The CLI hint in
format_context_hints() and the context-summary comment are updated to
match; agent↔agent turns still receive no forced anchor, preserving
deep-nesting coordination behavior.

DM turns already anchored to the triggering event id via the is_dm
branch; this change makes the non-DM branch match.

Tests updated:
- test_anchor_human_in_thread_uses_triggering_event — thread case now
  asserts TRIGGER_ID (was ROOT_ID) and renamed accordingly.
- test_anchor_agent_sender_but_human_tagged_flattens — same rename.
- test_anchor_unknown_identity_treated_as_human_fail_open — same rename.
- test_human_thread_reply_anchors_to_root_not_triggering_or_parent —
  inverted; now asserts anchor is the triggering event id and NOT the
  thread root or intermediate parent. Regression test for block#4072.
- test_reply_instruction_allows_explicit_root_post_requests — updated
  to assert triggering-id anchor, while still requiring the
  explicit-root escape hint text.
- test_reply_instruction_batched_last_event_is_threaded — asserts the
  anchor is the steering event id.
- test_steer_cross_thread_reply_targets_steering_message — asserts the
  anchor is the *steering* message's own id (matching the human-facing
  supersede semantics), not the steering thread's root.
- test_reply_instruction_present_for_channel_thread_reply — now the
  DM-mirror for non-DM; asserts triggering-id anchor.
- New test_anchor_human_nested_reply_in_thread_uses_triggering_event —
  specifically pins the depth≥2 case (root≠parent) so a regression in
  nested threading is caught even if the simple flat-L1 case regresses
  unnoticed.

Verification: cargo test -p buzz-acp --lib (663 passed), cargo clippy
-p buzz-acp --all-targets -- -D warnings.

Fixes block#4072.

Signed-off-by: Sarthak Singh <sarthak.singh@juspay.in>
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.

Agents should reply to the exact message that triggered them

1 participant