-
-
Notifications
You must be signed in to change notification settings - Fork 69.5k
message:sent internal hook never fires for direct agent responses #35557
Description
Bug type
Behavior bug (incorrect output/state without crash)
Summary
The message:sent internal hook does not fire when agents send direct responses to users. This prevents hooks that need to react to outbound messages (e.g., model indicators, logging, analytics) from working.
Steps to reproduce
- Create a managed hook directory at
~/.openclaw/hooks/test-hook/with HOOK.md containingevents: [message:sent] - Add a handler.js that logs to a file
- Restart the gateway - hook shows as registered:
Registered hook: test-hook -> message:sent - Send a message to the agent via any channel
- Observe the hook handler is never called
- Check gateway logs - no errors, hook is just silently skipped
Expected behavior
The message:sent hook should fire after each agent response, allowing hooks to track outbound messages for all sessions, not just mirrored ones.
Actual behavior
The hook never fires. No user-visible errors. The code includes a warning for this case: "session.agentId present without session key; internal message:sent hook will be skipped" - but the warning is not logged because the condition is silently skipped.
OpenClaw version
2026.3.2
Operating system
WSL2 (Windows 11) / Linux 6.6.87.2-microsoft-standard-WSL2
Install method
npm global
Logs, screenshots, and evidence
Impact and severity
No response
Additional information
Root Cause
In deliverOutboundPayloads, the session key for internal hooks is derived from:
const sessionKeyForInternalHooks = params.mirror?.sessionKey ?? params.session?.key;For direct agent responses (no mirror), sessionKeyForInternalHooks depends on params.session?.key. However, buildOutboundSessionContext() only sets session.key when a sessionKey parameter is explicitly provided:
const outboundSession = buildOutboundSessionContext({
cfg,
agentId: params.agentId,
sessionKey: params.mirror?.sessionKey // ← undefined for direct responses
});When sessionKey is undefined, buildOutboundSessionContext() returns an object without a key property, so params.session?.key is also undefined.
Suggested Fix
Either:
- Pass the session key through the call chain when building outbound context
- Derive session key from the agent context when mirror is not present
- Document that
message:senthooks only work for mirrored sessions
Workaround
None available for hook-based solutions. Use /status or ask the agent directly for model info.