#working-memory

4 messages · Page 1 of 1 (latest)

tough eagle
#

The hook file discovery works. The gateway loads managed hooks from
~/.openclaw/hooks/ and finds working-memory/ → reads HOOK.md → selects
handler.js as the handler (candidates list: handler.ts, handler.js, index.ts,
index.js — handler.mjs is not on that list, so your manual test is testing a
different file than what the gateway loads).

The HOOK.md metadata parsing probably works via a roundabout path: YAML
parsing fails on the trailing commas inside the flow mapping (YAML doesn't
allow them), so it falls back to the line-based parser which captures the
whole indented block as a raw multi-line string, then JSON5 successfully
parses it (JSON5 does allow trailing commas). End result: events are
extracted.

The message:sent event is conditionally gated. In deliver-DgXmvvc9.js:634-653:

const canEmitInternalHook = Boolean(params.sessionKeyForInternalHooks);
// ...
if (!canEmitInternalHook) return;
fireAndForgetHook(triggerInternalHook(createInternalHookEvent("message",
"sent", ...)))

More importantly: deliverOutboundPayloads is the channel outbound delivery
path — WhatsApp, Telegram, SMS, etc. The webchat/ACP UI is a direct WebSocket
response; it likely never calls this function, so message:sent may simply
never fire for webchat sessions.

hard mossBOT
haughty quarryBOT
#

Yep, that lines up with the code.

A few concrete confirmations from source:

  • Hook discovery only looks for handler.ts, handler.js, index.ts, index.js in src/hooks/workspace.ts, so handler.mjs will not load.
  • The weird HOOK.md parsing path is real. parseFrontmatterBlock tries YAML first, falls back to line parsing on YAML failure, then metadata gets parsed with JSON5. There’s even a test for the real bundled session-memory format in src/hooks/frontmatter.test.ts.
  • message:sent internal hooks are emitted from src/infra/outbound/deliver.ts, and only when sessionKeyForInternalHooks exists.
  • More importantly, webchat/internal sessions are not using that outbound path. In src/gateway/server-methods/chat.ts, INTERNAL_MESSAGE_CHANNEL replies are collected via createReplyDispatcher(... deliver: async (...) => deliveredReplies.push(...)), not deliverOutboundPayloads(...).

So I think your conclusion is right:

message:sent currently means “external outbound delivery happened”, not “assistant produced a reply in any surface”.

Docs say message:sent is “Outbound message delivered” https://docs.openclaw.ai/automation/hooks, but for webchat/ACP that effectively does not happen through the same transport layer.

If your goal is “run working-memory after assistant replies in ACP/webchat”, this looks like a real gap, not a bad hook install. Worth filing as a bug/feature request: https://github.com/openclaw/openclaw/issues