fix(buzz-acp): anchor replies for natively-steered events#1549
Conversation
When a message reaches an agent mid-turn via the goose-native steer path (try_native_steer), the steer body carried only the framing header, the event block, and the closing note — no reply-anchor instruction. The agent's only in-context --reply-to guidance was the stale anchor from its original prompt, so it replied into the old thread even when the steered message was top-level or belonged to a different thread. Observed in the wild: a top-level 'give me a status report' mention was answered inside the agent's old task thread. Every other delivery path already anchors: fresh top-level turns get append_new_thread_reply_instruction, fresh thread turns get append_reply_instruction, and the cancel+merge fallback re-derives the anchor in format_prompt from the last event. Native steer was the only path with no anchor at all. Fix: native_steer_reply_instruction derives the anchor from the steered event's own thread tags — its thread root when threaded, the event itself when top-level — mirroring resolve_reply_anchor, and is appended to the steer body after the event block. No profile lookup is available on this synchronous path, so no agent-to-agent exemption is applied; that matches turn_is_human_facing's documented fail-open policy (unknown identity is treated as human). The instruction is scoped to 'replies to this new message' so in-progress work keeps its original anchor. Tests pin both derivations (top-level anchors to the event, threaded anchors to the steered event's root, never the event id). Co-authored-by: Bradley Axen <baxen@squareup.com> Signed-off-by: Bradley Axen <baxen@squareup.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 885585188f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let tags = parse_thread_tags(event); | ||
| let event_id = event.id.to_hex(); | ||
| let mut s = String::new(); | ||
| match tags.root_event_id { |
There was a problem hiding this comment.
Preserve DM reply anchoring in native steers
When the in-flight channel is a DM, the normal prompt path applies DM-specific routing: top-level DM messages intentionally get no --reply-to, and DM thread replies anchor to the triggering event id rather than the thread root (format_prompt's is_dm branch, also pinned by test_reply_instruction_absent_for_dm_non_reply). This new helper only switches on thread tags and try_native_steer calls it without channel type, so the exact same DM message is routed differently whenever it arrives mid-turn via native steer: top-level DMs become threaded replies, and threaded DMs reply to the root instead of the current message. Please pass the DM/channel context into this derivation or suppress/adjust the instruction for DMs.
Useful? React with 👍 / 👎.
Problem
Reported in buzz-bugs: an agent working in a thread was asked for a status update via a new top-level mention, and replied inside its old task thread instead of the new message.
Trace from the live channel confirmed it's a real gap, not just LLM confusion: the top-level ask (
6d7d24c5…, no e-tags) was answered by the busy agent with an event e-tagged to its old thread root, while the two idle agents (fresh turns) replied to the right place.Root cause
When a message arrives mid-turn and is delivered via the goose-native steer path (
try_native_steer,lib.rs), the steer body isframing header + event block + closing note— no reply-anchor instruction. Every other delivery path anchors replies:append_new_thread_reply_instruction(anchor = triggering event)append_reply_instruction(anchor = thread root)format_promptre-derives the anchor from the last eventSo a natively-steered agent's only in-context
--reply-toguidance is the stale anchor from its original prompt — replying to the old thread is literally what its context tells it to do.Fix
queue::native_steer_reply_instructionderives an anchor from the steered event's own thread tags, mirroringresolve_reply_anchor:and appends the instruction to the steer body after the event block. The instruction is scoped to "replies to this new message" so the agent keeps its original anchor for in-progress work. No profile lookup exists on this synchronous path, so no agent↔agent exemption is applied — consistent with
turn_is_human_facing's fail-open policy (unknown → treat as human).Testing
cargo test -p buzz-acp --lib: 436 passed. fmt + clippy clean.Found and fixed by fable00 (agent) — thread: buzz-bugs
7c614ae5…