-
-
Notifications
You must be signed in to change notification settings - Fork 55.4k
Description
Summary
When a message_sending plugin hook cancels outbound delivery (returns { cancel: true }), the message_sent hook is not fired. This means plugins tracking delivery outcomes — audit logging, analytics, delivery confirmation — have no visibility into cancelled sends.
Severity
Medium — Affects plugins relying on message_sent for comprehensive delivery tracking. The send is correctly prevented, but the cancellation is silent to downstream observers.
Steps to Reproduce
- Register a plugin with both
message_sendingandmessage_senthooks:api.on("message_sending", (event) => { if (shouldBlock(event.content)) return { cancel: true }; }); api.on("message_sent", (event) => { console.log("SENT HOOK:", event.success, event.error); });
- Trigger an outbound message through
deliverOutboundPayloads(proactive/tool send path). - Have the
message_sendinghook return{ cancel: true }.
Expected
message_sent fires with { success: false, error: "canceled by message_sending hook" }.
Actual
message_sent does not fire. The cancellation is invisible to message_sent subscribers.
Root Cause
In src/infra/outbound/deliver.ts (line 488-489), when sendingResult?.cancel is true, the code does continue without calling emitMessageSent:
if (sendingResult?.cancel) {
continue; // BUG: skips emitMessageSent entirely
}Context
- The text-only and
sendPayloadsuccess paths formessage_sentwere fixed in commit1d8bda4a2(PR fix: complete message_sent hook dispatch coverage (follow-up to #14882) #15104), but the cancel path was overlooked. - PR feat(hooks): wire outbound message lifecycle hooks #12584 (open, Greptile score 4/5) explicitly handles this case by firing
message_sent(false, "canceled by message_sending hook")— the pattern we should follow. - This is a residual gap from the original hook wiring in PR fix: wire 9 unwired plugin hooks to core code #14882.
Fix
One-line addition — fire emitMessageSent(false, "canceled by message_sending hook") before the continue:
if (sendingResult?.cancel) {
emitMessageSent(false, "canceled by message_sending hook");
continue;
}A fix with 6 new tests (25 total passing) exists on branch fix/message-sent-hook-cancel-path.
Related
- message_sending hook not invoked for message tool sends (only agent responses) #16126 —
message_sendinghook not invoked for message tool sends - message_sending and message_sent plugin hooks never fire on common text delivery paths #15389 —
message_sendingandmessage_senthooks never fire on common text delivery paths - [Bug]: Plugin hooks: 9 of 14 registered hook types are never invoked (silent no-op) #14571 — 9 of 14 registered hook types are never invoked
- PR fix: wire 9 unwired plugin hooks to core code #14882 — Original (incomplete) hook wiring
- PR fix: complete message_sent hook dispatch coverage (follow-up to #14882) #15104 — Partial fix for
message_senton success paths - PR feat(hooks): wire outbound message lifecycle hooks #12584 — Comprehensive hook wiring (open, handles cancel path correctly)