feat(hooks): add message:sent and message:received internal hook events#6384
feat(hooks): add message:sent and message:received internal hook events#6384heybeaux wants to merge 5 commits intoopenclaw:mainfrom
Conversation
|
Hi maintainers, Just following up on this PR. Greptile bot feedback has been addressed:
The CI failures appear to be unrelated to this PR — they're in Swift lint and Windows build, while this change only touches TypeScript hook dispatch code. Happy to rebase if there are conflicts, but wanted to check if a maintainer could re-run CI or confirm these failures are pre-existing. This feature would enable automatic memory capture for AI agents via the hook system. Appreciate any guidance on getting it over the line. |
fdd23a7 to
bd107e2
Compare
|
👍 This feature would be very valuable for our Mission Control dashboard integration. We're building a real-time agent activity tracker that needs to sync tool calls and messages to an external dashboard. Looking forward to this landing! Use case: Automatic status updates in a custom dashboard showing what the agent is currently doing, token usage, and activity history. |
|
@f2daz It sounds like a lot of projects, both existing and in development, would benefit from this feature. I'm hopeful that we'll see movement in the next week or so. It's incredible to see such a busy open source project. |
|
📋 Duplicate triage note: PR #6797 appears to implement the same fix. Consider consolidating or closing one in favor of the other. |
|
Hey @Glucksberg, thanks for flagging the overlap with #6797. I've taken a look at both implementations and they're solving the same problem with very similar approaches — dedicated A few observations:
I'm very open to consolidating — the goal is getting this feature landed, not who gets credit. A few paths forward:
Whatever gets the feature across the finish line works for me. 🤝 |
Implements the message lifecycle hooks documented as 'Future Events' in the hooks documentation. These events enable extensions to observe inbound and outbound messages for logging, analytics, memory systems, and archival. New events: - message:received: triggered when an inbound message is processed - message:sent: triggered after an outbound message is successfully delivered Both events include rich context (text, channel, chatType, sender info, media URLs) and are fired asynchronously so they never block message processing. Includes: - 6 test cases covering event triggering, general/specific handler routing, media fields, error isolation, and type validation - Documentation update moving these from 'Future Events' to documented events Combines approaches from prior community PRs openclaw#6384, openclaw#6797, and openclaw#9859. Resolves openclaw#12775, openclaw#8807, openclaw#13004 Related: openclaw#5354, openclaw#12867, openclaw#12914
|
hey @heybeaux — running message hooks in production (via backport of #6797, same concept as yours) for a week now. 550+ events, 3 hooks built on top (memory, DLP, multi-bot sync). found a real gap and opened a discussion with a proposal to extend the lifecycle: #14539 short version: both PRs solve the same core problem. would be great to coordinate — happy to contribute groupId fix and preprocessed to whichever PR the maintainers prefer. |
|
Hey @matskevich — love that you've been battle-testing this in production. 550+ events with zero crashes is exactly the validation this feature needs. The I'm happy to add Your proposed Plan:
If you want to co-author or review, happy to coordinate. Let's get this landed. 🤝 |
b516878 to
6b6762d
Compare
Implements the internal hook events documented as 'Future Events' in the hooks
documentation. These events enable extensions to observe message lifecycle:
- message:received: Triggered when an inbound message is processed
- Includes: text, channel, chatType, from/to, senderId, senderName,
messageId, threadId, timestamp, mediaUrls, mediaTypes
- Triggered in dispatch-from-config.ts after duplicate check
- message:sent: Triggered when an outbound message is successfully delivered
- Includes: text, channel, chatType, kind (tool/block/final),
mediaUrl, mediaUrls, timestamp
- Triggered in reply-dispatcher.ts after successful delivery
Use cases:
- Agent memory systems (e.g., Engram) that need to persist conversations
- Analytics and logging plugins
- Message archival and search indexing
- Conversation export features
API example:
registerInternalHook('message:received', async (event) => {
await saveToMemory(event.context.text, event.sessionKey);
});
registerInternalHook('message:sent', async (event) => {
await logOutbound(event.context.text, event.context.kind);
});
Closes openclaw#5354 (NOT_PLANNED - now implemented via PR)
- Remove duplicate timestamp from hook context (use event.timestamp) - Make sessionKey handling consistent (fire even with empty key, fall back to "") - Add debug logging for hook errors (match dispatch-from-config pattern)
6b6762d to
a15c032
Compare
…ding Fires after applyMediaUnderstanding() and applyLinkUnderstanding(), before agent processing. Voice messages now have transcripts, images have descriptions, and links have summaries when this hook fires. Also adds groupId to message:received internal hook context. Addresses discussion openclaw#14539 (three-event lifecycle proposal).
a15c032 to
16c9d44
Compare
|
Updated — PR now implements the full three-event lifecycle from discussion #14539: What's new in the latest push:
This addresses @matskevich's production finding that 4 commits, 7 files, +172 lines. Ready for review. |
|
Closing as duplicate of #14196. If this is incorrect, comment and we can reopen. |
Summary
Implements the internal hook events documented as "Future Events" in the hooks documentation. These events enable extensions to observe the complete message lifecycle.
Related Issue
This PR addresses the functionality requested in #5354, which was closed as
NOT_PLANNEDdue to maintainer bandwidth. As suggested, submitting a PR instead.Changes
New Events
message:received- Triggered when an inbound message is processedtext,channel,chatType,from,to,senderId,senderName,senderUsername,messageId,threadId,timestamp,accountId,mediaUrls,mediaTypesdispatch-from-config.tsafter duplicate check, alongside the existing plugin hookmessage:sent- Triggered when an outbound message is successfully deliveredtext,channel,chatType,kind(tool/block/final),mediaUrl,mediaUrls,timestampreply-dispatcher.tsafter successful deliveryImplementation Details
"message"toInternalHookEventTypeinsrc/hooks/internal-hooks.tsmessage:receivedindispatchReplyFromConfig()for inbound messagesmessage:sentin the reply dispatcher after delivery successsessionKey,channel, andchatTypeoptions toReplyDispatcherOptionsfor hook contextdispatchInboundMessageWithDispatcheranddispatchInboundMessageWithBufferedDispatcherto inject session context into dispatcher optionsUse Cases
Example Usage
Testing
Checklist
createInternalHookEvent,triggerInternalHook)Greptile Overview
Greptile Summary
Adds two new internal hook events to the existing internal hook registry:
message:receivedis emitted during inbound message processing (after duplicate-check) with message/metadata context, andmessage:sentis emitted after successful outbound delivery from the reply dispatcher. To support outbound context, dispatcher options are extended to carrysessionKey,channel, andchatType, and the inbound dispatch entrypoints now inject those values from the finalized inbound context.Confidence Score: 4/5
(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!