You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
provider-acp: no consumption path for agent-wake notifications — ACP agents with settled background work can't be resumed (OMP async-job delivery) #2461
When an ACP agent settles background work after the client-owned prompt has completed — OMP's async-job auto-delivery is the concrete case — the only v1-legal way to surface that work is a private, capability-gated notification asking the client to prompt again. OMP is preparing exactly that (option (b) in can1357/oh-my-pi#9157: initialize_meta capability + _-prefixed wake notification + parked delivery, already endorsed by two other ACP consumers). bb has no consuming half:
handleAgentNotification drops every notification that is not session/update — a wake has no entry point.
No path synthesizes a client turn on an agent's behalf: client/turn/requested has source producers only for spawn/tell.
activeBackgroundAgentCount counts only Claude-Code backgroundTask rows, so bb cannot even show that an ACP agent has work in flight.
This tracks the bb side: capability handshake, notification routing, synthetic resume, and background-task materialization. It is the delivery half of #2122 (which tracks rendering of unprompted session/update frames): on OMP 18.x there are no frames to render — verified live in production below. Work shipped to git while the thread sat idle forever.
2. Versions and environment
bb 0.40.1-nightly.32914368061.1 (desktop, macOS arm64); source audited at d3f7a90 (main).
Provider acp-omp: OMP 18.0.5 via omp acp.
Production thread thr_5esghkmr5x, window 2026-08-26 00:50–01:06 UTC.
Start a thread on acp-omp and give the agent work that ends the turn with background agents still running (OMP's "ending the turn for auto-delivery" — its core resume mechanism).
Wait minutes for the agents to settle.
OMP resumes the orchestrator detached inside its own process; the follow-up turn runs to completion (verification gate, commit, final summary).
The bb thread never reacts: no turn, no message, no error; idle forever.
4. Expected vs actual
Observed live (all UTC, 2026-08-26):
00:50:37 turn/completed — orchestrator ends turn, 2 background agents in flight
01:01–01:04 agents finalize inside OMP
01:05:32–53 OMP's detached resume completes: verification gate passes,
commit 75e0691 lands 01:05:34 (14 files, +793/−149),
close-out summary written to the OMP session transcript only
bb events: zero turn events; one acp/fs/write at 01:05:32 surfaced as a
hidden provider/unhandled row; no session/update of any kind
Expected: the thread reports the follow-up (summary + commit), or at minimum a resumable state. Actual: complete silence — the work exists only in git and ~/.omp/agent/sessions/, and the user has to learn it shipped from elsewhere.
5. Evidence
Each side of the gap, at d3f7a90:
Routing: handleAgentNotification in packages/provider-bridge-acp/src/bridge/bridge.ts (L2504–L2511) returns immediately for any method !== "session/update" — everything else an agent sends is dropped without logging.
Turn initiation: packages/domain/src/thread-events.ts types client/turn/requested with source: z.enum(["spawn", "tell"]) (L119) — no producer can express an agent-initiated request, even though initiator already includes "agent" (invariant comment at L121) and continuationOfRequestId exists unused (L117–118). The event surface is half-ready.
Visibility: activeBackgroundAgentCount is SQL over backgroundTask rows that ACP providers never write — bb cannot show "N agents running" for OMP.
Send path: the provider-retry plumbing (continueCandidate, plugins/provider-retry/src/service.ts L505) already sends agent-only continuations with a legible decline (input-not-accepted when the session can't accept) — the same shape a wake-answer needs.
Not agent reaping: the omp acp process stayed alive through the whole window and completed the follow-up in-process.
Not permission stalls: tools.approvalMode: yolo.
Not OMP failing to resume: the detached resume ran and finished; the loss is at the ACP boundary.
Not fixable agent-side alone: ACP v1 forbids continuing a settled turn via session/update (only _meta and _-prefixed extensions are legal); a wake must be answered by a client session/prompt.
7. Suggested priority and effort
Same population as #2122 — every acp-omp thread whose turn ends with background work — now with guaranteed rather than heuristic loss. P1; medium effort, additive and fully gated so nothing changes for agents that don't advertise:
Advertise clientCapabilities._meta["bb.dev"] = { agentWake: 1 } at initialize; treat agentCapabilities._meta["oh-my-pi"].agentWake as the agent-side opt-in.
Route _-prefixed notifications through handleAgentNotification instead of dropping them.
On wake: synthetic resume on the existing send path, emitting client/turn/requested with initiator: "agent" and continuationOfRequestId (extend the source enum with a "wake" member or equivalent); decline legibly (input-not-accepted) if the session can't accept.
Materialize backgroundTask rows for ACP agents with work in flight so activeBackgroundAgentCount and the UI count them.
1. Summary
When an ACP agent settles background work after the client-owned prompt has completed — OMP's async-job auto-delivery is the concrete case — the only v1-legal way to surface that work is a private, capability-gated notification asking the client to prompt again. OMP is preparing exactly that (option (b) in can1357/oh-my-pi#9157:
initialize_metacapability +_-prefixed wake notification + parked delivery, already endorsed by two other ACP consumers). bb has no consuming half:handleAgentNotificationdrops every notification that is notsession/update— a wake has no entry point.client/turn/requestedhassourceproducers only for spawn/tell.activeBackgroundAgentCountcounts only Claude-CodebackgroundTaskrows, so bb cannot even show that an ACP agent has work in flight.This tracks the bb side: capability handshake, notification routing, synthetic resume, and background-task materialization. It is the delivery half of #2122 (which tracks rendering of unprompted
session/updateframes): on OMP 18.x there are no frames to render — verified live in production below. Work shipped to git while the thread sat idle forever.2. Versions and environment
d3f7a90(main).acp-omp: OMP 18.0.5 viaomp acp.thr_5esghkmr5x, window 2026-08-26 00:50–01:06 UTC.d3f7a90: neither Vouch agent-initiated ACP turns so async job delivery renders #2123 nor Bracket agent-initiated ACP turns so unprompted work renders #2220 is merged — this build ships no vouched-turn code, so nothing on the bb side catches any shape of this failure.3. Steps to reproduce
acp-ompand give the agent work that ends the turn with background agents still running (OMP's "ending the turn for auto-delivery" — its core resume mechanism).4. Expected vs actual
Observed live (all UTC, 2026-08-26):
Expected: the thread reports the follow-up (summary + commit), or at minimum a resumable state. Actual: complete silence — the work exists only in git and
~/.omp/agent/sessions/, and the user has to learn it shipped from elsewhere.5. Evidence
Each side of the gap, at
d3f7a90:handleAgentNotificationinpackages/provider-bridge-acp/src/bridge/bridge.ts(L2504–L2511) returns immediately for anymethod !== "session/update"— everything else an agent sends is dropped without logging.packages/domain/src/thread-events.tstypesclient/turn/requestedwithsource: z.enum(["spawn", "tell"])(L119) — no producer can express an agent-initiated request, even thoughinitiatoralready includes"agent"(invariant comment at L121) andcontinuationOfRequestIdexists unused (L117–118). The event surface is half-ready.activeBackgroundAgentCountis SQL overbackgroundTaskrows that ACP providers never write — bb cannot show "N agents running" for OMP.continueCandidate,plugins/provider-retry/src/service.tsL505) already sends agent-only continuations with a legible decline (input-not-accepted when the session can't accept) — the same shape a wake-answer needs.agentCapabilities._meta["oh-my-pi"].agentWake/clientCapabilities._meta["bb.dev"].agentWakehandshake,PromptResponse._meta.pendingAsyncJobs, an_-prefixed wake notification, and delivery parked on the existing hidden-message queue until the client prompts.6. What I ruled out
session/updateframes arrive after the prompt settles — verified live here, and independently observed in Bracket agent-initiated ACP turns so unprompted work renders #2220's verification against real omp ("never emit session/update once a session/prompt has settled — omp's ACP prompt handler returns early"). There is nothing to bracket.omp acpprocess stayed alive through the whole window and completed the follow-up in-process.tools.approvalMode: yolo.session/update(only_metaand_-prefixed extensions are legal); a wake must be answered by a clientsession/prompt.7. Suggested priority and effort
Same population as #2122 — every
acp-ompthread whose turn ends with background work — now with guaranteed rather than heuristic loss. P1; medium effort, additive and fully gated so nothing changes for agents that don't advertise:clientCapabilities._meta["bb.dev"] = { agentWake: 1 }at initialize; treatagentCapabilities._meta["oh-my-pi"].agentWakeas the agent-side opt-in._-prefixed notifications throughhandleAgentNotificationinstead of dropping them.client/turn/requestedwithinitiator: "agent"andcontinuationOfRequestId(extend thesourceenum with a"wake"member or equivalent); decline legibly (input-not-accepted) if the session can't accept.backgroundTaskrows for ACP agents with work in flight soactiveBackgroundAgentCountand the UI count them.Agent is already processingrejection — queue-and-retry with backoff rather than failing the synthetic turn.Sequencing: lands after (or with) the OMP-side capability.