block / block/buzz

buzz-acp: native mid-turn steer sends no reply destination, so the message is answered in the previous thread

Open
#6,856 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

`buzz-acp` has two transports for delivering a message into a turn that is already running, and only one of them tells the agent where to reply. A message steered in from thread B gets answered in thread A. Thread B shows no reply, so from the human's side the second message looks unanswered.

It is the default path, not an edge case: `--multiple-event-handling` defaults to `steer` (`config.rs:362`), native steering is tried first, and the cancel+merge fallback — which *does* supply a destination — runs only when native declines. Not goose-specific either: any adapter advertising `_meta.steering.supported` is affected, `claude-agent-acp` included.

**Steps to reproduce**

1. Run an agent under `buzz-acp` at default settings, on an adapter advertising `_meta.steering.supported`.
2. `@mention` it in thread A. It starts a turn.
3. Before that turn finishes, `@mention` it in **thread B** — a different thread, same channel. This is delivered as a native mid-turn steer.
4. **Expected:** the answer lands in thread B. **Actual:** it lands in thread A.

**Root cause**

`try_native_steer` (`lib.rs:3635`) hand-assembles its own prompt instead of going through `queue::format_prompt`, where the reply anchor is resolved (`queue.rs:1604`). With no destination in the steered prompt, the newest one left in the agent's context belongs to the turn already in flight. The rule is not missing — this transport never calls it.

**Proposed solution**

Move ownership of the steer body into `queue`, so the anchor cannot be skipped by whoever assembles the prompt:

- Add `queue::format_native_steer_prompt` — framing, event block, **and** the resolved reply anchor.
- Make `native_steer_framing` and `format_event_block` private to `queue`, so hand-assembly cannot recur.
- Fold `format_prompt`'s inline DM branch into `resolve_reply_anchor`. One function should hold the rule; that duplication is how the transports diverged.

Only per-event routing is added. Standing context, channel metadata and history stay out, preserving the delta property that makes non-cancelling steering worth having.

**Related**

**#5190** is the closest: the same symptom from the agent's side, attributed to a `[Context]` block carrying the in-flight turn's root. We think that is what this absence looks like from inside a session, and filed separately only because the fix location differs — recomputing per event is what `format_prompt` already does; the gap is a transport that never calls it. **Say the word and we will fold this into #5190.**

**#1549** is the closest prior art — same root cause, approved, then closed unmerged by its own author with no reason given. It never reached `main`. **If it was closed for a reason that still applies, we would rather hear it now than rediscover it.**

Nearby but distinct: #5839, #5219, #3075, #4072 — characterised in the comment.

**Version and platform**

`block/buzz@main` at `52621c09b`; macOS (Darwin 25.6.0), self-hosted relay, desktop-managed agent, default settings.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.