block / block/buzz

buzz-acp: non-steerable ACP agents (oh-my-pi/omp) silently drop mid-turn messages (ExpectedRunIdMissing deadlock)

Open
#4,189 3 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

### Non-steerable ACP agents (e.g. oh-my-pi/omp) silently drop mid-turn messages

**Environment**
- repo: block/buzz @ ac4fa13, buzz-acp 0.5.3
- agent: `omp acp` (oh-my-pi 17.2.3, an ACP server that does not advertise steering)
- relay: hosted community, `subscribe=Mentions`, `meh=Steer`, `parallelism=10`, `max_turn_duration=7200`

**Symptom**
The agent connects fine (owner resolved, channel subscribed, presence online). But every user message is logged and dropped:

```
steer: no active_run_id and agent did not advertise _session/steering — falling back to cancel+merge
non-cancelling steer ack received … ack=Ok(Err(ExpectedRunIdMissing)) signal_fallback=true
```

No `session/prompt` ever fires; the user sees a "typing" indicator but never receives a reply. Reproduced on every message across multiple sessions.

**Root cause (from source)**
1. `lib.rs` relay-event gate (`if accepted && queue.is_channel_in_flight(…)`) routes an event to a steer signal when the channel is marked in-flush.
2. omp advertises neither `_meta.steering.supported` nor goose `activeRunId`, so `try_native_steer` returns false → falls back to `signal_in_flight_task` (`ControlSignal::Steer`).
3. `acp.rs` steer arm acks `SteerError::ExpectedRunIdMissing`; the main loop maps that to the cancel+merge fallback.
4. `pool.rs:1954` `if agent.acp.has_in_flight_prompt()` is **false** for omp → the "already completed" branch runs, and for `Steer` `apply_completed_before_control_signal` does **nothing** — the message is stranded.
5. The queue stays `in_flight` (deadline = `max_turn_duration`, kept alive by `extend_in_flight_deadline`) → `flush_next` excludes the channel → the queued event is never re-dispatched.

Steerable agents (claude-agent-acp, goose) don't hit this because their turn exposes a cancel/merge target.

**Proposed fix direction**
When a mode-gate Steer/cancel is required for a channel whose agent has **no active in-flight prompt** (non-steerable / stale `in_flight`), do not fire a steer signal into a void — release the channel (`queue.mark_complete(channel_id)`) and let `dispatch_pending` re-prompt the queued event as a fresh `session/prompt`. A check of the channel's prompt-task agent state (or completion-time reconciliation) distinguishes "genuinely in-flight" from "stale".

**Acceptance**
With a non-steerable ACP agent: sending a DM should produce a real `session/prompt` and the reply should be published. Steerable agents must remain unchanged.

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.