Skip to content

message:sent internal hook never fires for direct agent responses #35557

@nathanriggs

Description

@nathanriggs

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

  1. Create a managed hook directory at ~/.openclaw/hooks/test-hook/ with HOOK.md containing events: [message:sent]
  2. Add a handler.js that logs to a file
  3. Restart the gateway - hook shows as registered: Registered hook: test-hook -> message:sent
  4. Send a message to the agent via any channel
  5. Observe the hook handler is never called
  6. 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:

  1. Pass the session key through the call chain when building outbound context
  2. Derive session key from the agent context when mirror is not present
  3. Document that message:sent hooks only work for mirrored sessions

Workaround

None available for hook-based solutions. Use /status or ask the agent directly for model info.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingbug:behaviorIncorrect behavior without a crash

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions