← Back to PRs

#19922: feat(hooks): add message:received and message:sent hook events

by NOVA-Openclaw open 2026-02-18 09:25 View on GitHub →
size: M
## Summary Add hook events for the message lifecycle, enabling workspace hooks to trigger on incoming and outgoing messages (e.g., memory extraction, semantic recall, logging). ### Changes - **`src/hooks/message-hooks.ts`** — New file with `triggerMessageReceived` and `triggerMessageSent` helpers - **`src/auto-reply/dispatch.ts`** — Wire `message:received` trigger before agent processing in `dispatchInboundMessage()` - **`src/auto-reply/reply/reply-dispatcher.ts`** — Wire `message:sent` trigger after successful delivery; add `hookContext` option to `ReplyDispatcherOptions` - **`src/hooks/hooks.ts`** — Export message hook types - **`src/hooks/message-hooks.test.ts`** — Unit tests for both triggers - **`src/auto-reply/dispatch.test.ts`** — **Regression test** ensuring `dispatchInboundMessage` calls `triggerMessageReceived` (prevents silent removal by future refactors) ### Context Supersedes #6797. The original PR was merged into our fork but the `triggerMessageReceived()` call site was silently dropped by commit d5e25e0ad ("refactor: centralize dispatcher lifecycle ownership") when `dispatch.ts` was rewritten. This went undetected because there was no regression test. This updated PR: 1. Rebases cleanly onto current `main` 2. Adapts to the new `withReplyDispatcher` pattern in `dispatch.ts` 3. Adds a dedicated regression test to prevent recurrence ### Hook Events | Event | Fires when | Location | |---|---|---| | `message:received` | Inbound message about to be processed | `dispatchInboundMessage()` | | `message:sent` | Outbound reply successfully delivered | `createReplyDispatcher()` delivery callback | ### Use Cases - Memory extraction from incoming messages - Semantic recall injection into agent context - Activity tracking and logging - Message analytics Closes #5053 <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR adds `message:received` and `message:sent` hook events to the internal hook system, enabling workspace hooks to trigger on inbound and outbound messages. The `message:received` hook is wired into `dispatchInboundMessage()` and fires correctly before agent processing. A regression test is included to prevent the call site from being silently dropped again. **Key issues found:** - **Conflicting context shapes:** The new `MessageReceivedContext` and `MessageSentContext` types in `message-hooks.ts` use different field names (`message`, `senderId`, `channel`, `text`, `target`) than the existing `MessageReceivedHookContext` and `MessageSentHookContext` types in `internal-hooks.ts` (`from`, `content`, `channelId`, `to`, `success`). The existing type guards (`isMessageReceivedEvent`, `isMessageSentEvent`) will **never match** events produced by the new triggers, which could break consumers relying on those guards. - **`message:sent` hook is dead code in production:** The `hookContext` option was added to `ReplyDispatcherOptions`, but no channel dispatcher (Signal, Slack, Discord, iMessage, webchat) passes it. The `message:sent` hook will never fire until callers are wired up. - The `.gitignore` addition for `openclaw-*.tgz` is unrelated housekeeping. <h3>Confidence Score: 2/5</h3> - This PR has functional issues — conflicting type shapes break existing type guards, and the message:sent hook is effectively dead code. - Score of 2 reflects two significant issues: (1) the new hook context shapes are incompatible with existing type guards in internal-hooks.ts, which will cause isMessageReceivedEvent/isMessageSentEvent to return false for events from these triggers, and (2) the message:sent hook is never triggered in production because no dispatcher caller passes hookContext. - Pay close attention to `src/hooks/message-hooks.ts` (conflicting context types) and `src/auto-reply/reply/reply-dispatcher.ts` (unwired hookContext option). <sub>Last reviewed commit: 871a678</sub> <!-- greptile_other_comments_section --> <sub>(5/5) You can turn off certain types of comments like style [here](https://app.greptile.com/review/github)!</sub> **Context used:** - Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8)) <!-- /greptile_comment -->

Most Similar PRs