← Back to PRs

#11597: feat(hooks): implement message:received hook

by gnufoo open 2026-02-08 01:50 View on GitHub →
docs stale
## Summary Implements the `message:received` hook that was listed under "Future Events" in the docs. This hook triggers when a message is received before agent processing. ## Motivation This enables custom hooks to: - Log/analyze incoming messages in real-time - Build experiential memory systems that score message importance - Implement custom message filtering or tagging - Track conversation patterns ## Implementation - Added `message` to `InternalHookEventType` - Added `MessageReceivedHookContext` and `MessageReceivedHookEvent` types - Modified `dispatchInboundMessage` to trigger the hook - Hook fires asynchronously (fire-and-forget) to avoid blocking message processing - Commands (starting with `/`) do not trigger this hook (they have their own hooks) ## Context Fields | Field | Type | Description | |-------|------|-------------| | `body` | string | Message text | | `rawBody` | string? | Raw message without structural context | | `senderId` | string? | Sender identifier | | `channel` | string? | Originating channel (telegram, whatsapp, etc.) | | `chatType` | string? | direct/group | | `messageId` | string? | Provider message ID | | `replyToId` | string? | Reply-to ID if applicable | | `wasMentioned` | boolean? | Whether bot was mentioned | | `workspaceDir` | string? | Agent workspace directory | ## Example Usage ```typescript // In a custom hook handler.ts const handler: HookHandler = async (event) => { if (event.type !== "message" || event.action !== "received") { return; } const { body, senderId, channel } = event.context; console.log(`Message from ${senderId} on ${channel}: ${body}`); // Score importance, save to memory, etc. }; export default handler; ``` ## Testing - Added unit tests for the hook trigger - Verified commands do not trigger the hook - Verified empty messages do not trigger the hook ## Documentation - Updated `docs/automation/hooks.md` to move `message:received` from Future Events to implemented - Documented context fields Co-authored-by: Tony Xia <xia.tony@gmail.com> <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> Implements a new internal hook event `message:received` and wires it into the inbound message dispatch path so custom hooks can observe non-command messages before agent processing. Adds the corresponding internal hook event types/guards, updates hook documentation, and adds unit tests intended to verify the hook fires for normal messages and not for commands/empty bodies. <h3>Confidence Score: 3/5</h3> - This PR is close to mergeable but has test reliability issues and a likely mismatch between documented and actual command suppression behavior. - Core hook wiring is straightforward, but the added Vitest tests use `vi.mock()` inside `it()` blocks (non-deterministic due to hoisting/module cache) and the command-skip logic in `dispatchInboundMessage` only checks `Body/RawBody`, which may not cover all command inputs used elsewhere in the pipeline. - src/auto-reply/dispatch-hooks.test.ts, src/auto-reply/dispatch.ts <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs