feat(884): persistent perm_rx lock-holder for Matrix bot
Before: handle_message.rs acquired services.perm_rx only while processing one chat message and dropped it on chat_fut completion. The moment the bot wasn't actively responding, prompt_permission auto-denied any spawned coder bash call as "no interactive session" — making unattended coder work impossible. Now: a permission_listener task is spawned at bot startup and holds perm_rx for the bot's lifetime. Permission requests are forwarded to the first configured Matrix room, replies resolved by the existing on_room_message handler via pending_perm_replies. Per-message acquire is gone from handle_message.rs (chat_fut just awaits cleanly). - New module: chat/transport/matrix/bot/permission_listener.rs. - Wired into run_bot before BotContext construction; bot_sent_event_ids is hoisted out so the listener and the rest of the bot share it. - handle_message.rs no longer touches perm_rx. - diagnostics/permission.rs comment updated to reflect the new reality. - Regression test asserts the listener forwards a PermissionForward to the target room and records the pending reply key — exactly the path that was broken when no chat_fut was in flight. Discord/Slack/WhatsApp transports still acquire perm_rx per message (commands.rs:368 / commands/llm.rs:83 / commands/llm.rs:82). They are not the active transport in this deployment so their per-message acquire remains dormant; the same listener pattern should be applied to them as follow-up work in 884 phase 2.
This commit is contained in:
@@ -30,13 +30,12 @@ pub(crate) async fn tool_prompt_permission(
|
||||
}
|
||||
|
||||
// Auto-deny immediately if no interactive session is currently listening on
|
||||
// perm_rx. Interactive sessions (WebSocket, Matrix bot chat) hold the
|
||||
// perm_rx lock for the duration of a chat. If try_lock succeeds, nobody is
|
||||
// listening — this is a background agent call that should never reach chat.
|
||||
//
|
||||
// Without this check, agent permission requests queue in the channel and
|
||||
// get forwarded to Matrix/Slack/etc. at the start of the next user session,
|
||||
// flooding chat with stale agent prompts.
|
||||
// perm_rx. Story 884 made the Matrix bot hold this lock for its lifetime
|
||||
// via the permission_listener task spawned at startup, so requests reach
|
||||
// chat asynchronously regardless of whether a chat message is in flight.
|
||||
// Other transports (Discord/Slack/WhatsApp) still acquire per message; if
|
||||
// none is active, try_lock succeeds — auto-deny so background agent calls
|
||||
// don't queue and flood chat at the next user session.
|
||||
if ctx.services.perm_rx.try_lock().is_ok() {
|
||||
crate::slog!(
|
||||
"[permission] Auto-denied '{tool_name}' (no interactive session — agent mode)"
|
||||
|
||||
Reference in New Issue
Block a user