Skip to content

feat(hooks): wire outbound message lifecycle hooks#12584

Open
vincentkoc wants to merge 15 commits intoopenclaw:mainfrom
vincentkoc:vincentkoc-code/hooks-message-lifecycle
Open

feat(hooks): wire outbound message lifecycle hooks#12584
vincentkoc wants to merge 15 commits intoopenclaw:mainfrom
vincentkoc:vincentkoc-code/hooks-message-lifecycle

Conversation

@vincentkoc
Copy link
Contributor

@vincentkoc vincentkoc commented Feb 9, 2026

Why

Message lifecycle hooks were not fully wired across outbound delivery paths, limiting observability and intervention points for message guardrails. This PR completes outbound lifecycle wiring and propagates session context so hook consumers can attribute events reliably.

Detailed Changes

  • Wired outbound plugin hooks in delivery pipeline:
    • message_sending
    • message_sent (success/failure/cancel-aware)
  • Added message hook context fields in outbound flow:
    • sessionKey
    • sessionId
  • Added sessionKey into message_received hook context from dispatch flow
  • Applied session-key normalization touch-up in dispatch store lookup path

Related Links and Issues

Greptile Overview

Greptile Summary

This PR completes wiring for outbound message lifecycle plugin hooks by invoking message_sending (with cancel/modify support) and message_sent (success/failure/cancel-aware) across outbound delivery paths, including text chunking, Signal chunk formatting, and media sends. It also extends hook context with sessionKey/sessionId and propagates these fields through several call sites (gateway send, cron isolated-agent, heartbeat, auto-reply routing) so hook consumers can better attribute events.

Core changes live in src/infra/outbound/deliver.ts, which now runs the hooks around per-chunk/per-attachment sends and ensures failures are attributed to the attempted content. Tests were expanded substantially in src/infra/outbound/deliver.test.ts to cover chunk rewrite limits, cancel behavior, and accurate failure reporting.

Confidence Score: 4/5

  • This PR is close to safe to merge, but there is a concrete session-context propagation bug that undermines the stated observability goal in at least one outbound send path.
  • Most hook wiring changes in deliver.ts are internally consistent and are backed by new regression tests for chunk rewrite/cancel/failure attribution. However, sendMessage() appears to pass sessionKey from the mirror config rather than from the actual session context, so hook consumers will still miss session attribution in common direct-send flows unless this is corrected.
  • src/infra/outbound/message.ts

@vincentkoc vincentkoc marked this pull request as ready for review February 9, 2026 10:41
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@vincentkoc vincentkoc marked this pull request as draft February 9, 2026 16:43
@openclaw-barnacle openclaw-barnacle bot added the docs Improvements or additions to documentation label Feb 9, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

src/gateway/server-methods/send.ts
Missing session context propagation

deliverOutboundPayloads now accepts sessionKey/sessionId for message hook attribution, but this call site doesn’t pass either, so outbound message_sending/message_sent hooks invoked from the gateway send endpoint will still have undefined session fields. If hook consumers rely on session attribution (per PR description), this path won’t work as intended.

Also appears in src/infra/outbound/message.ts:162-179, src/auto-reply/reply/route-reply.ts:118-136, src/infra/heartbeat-runner.ts:803-820, src/cron/isolated-agent/run.ts:528-537.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/gateway/server-methods/send.ts
Line: 168:191

Comment:
**Missing session context propagation**

`deliverOutboundPayloads` now accepts `sessionKey`/`sessionId` for message hook attribution, but this call site doesn’t pass either, so outbound `message_sending`/`message_sent` hooks invoked from the gateway `send` endpoint will still have undefined session fields. If hook consumers rely on session attribution (per PR description), this path won’t work as intended.

Also appears in `src/infra/outbound/message.ts:162-179`, `src/auto-reply/reply/route-reply.ts:118-136`, `src/infra/heartbeat-runner.ts:803-820`, `src/cron/isolated-agent/run.ts:528-537`.

How can I resolve this? If you propose a fix, please make it concise.

@openclaw-barnacle openclaw-barnacle bot added the gateway Gateway runtime label Feb 9, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

src/infra/outbound/deliver.ts
Incorrect failure hook content

In the chunked send loops, message_sent is only emitted on the success path. If handler.sendText(...) (or sendSignal(...) in sendSignalTextChunks) throws, control jumps to the outer payload catch, which calls runMessageSentHook(attemptedSendContent, ...). But attemptedSendContent is only tracked for the payload/media paths, not for per-chunk text sends, so the failure message_sent.content can be wrong (often the full original payload text rather than the specific chunk that failed). This breaks downstream auditing/guardrails that expect the attempted chunk content.

Also affects sendSignalTextChunks where rewritten chunks are sent in an inner loop without updating any payload-scoped attempted content.

Also appears in src/infra/outbound/deliver.ts around 379-402.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/infra/outbound/deliver.ts
Line: 324:327

Comment:
**Incorrect failure hook content**

In the chunked send loops, `message_sent` is only emitted on the success path. If `handler.sendText(...)` (or `sendSignal(...)` in `sendSignalTextChunks`) throws, control jumps to the outer payload `catch`, which calls `runMessageSentHook(attemptedSendContent, ...)`. But `attemptedSendContent` is only tracked for the payload/media paths, not for per-chunk text sends, so the failure `message_sent.content` can be wrong (often the full original payload text rather than the specific chunk that failed). This breaks downstream auditing/guardrails that expect the attempted chunk content.

Also affects `sendSignalTextChunks` where rewritten chunks are sent in an inner loop without updating any payload-scoped attempted content.

Also appears in `src/infra/outbound/deliver.ts` around 379-402.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

src/auto-reply/reply/dispatch-from-config.ts
Inconsistent session key lookup

This file still does store[sessionKey.toLowerCase()] ?? store[sessionKey] when reading the session store, but elsewhere the PR notes a “session-key normalization touch-up”. If other code paths now normalize differently (e.g., via a shared helper), leaving this ad-hoc normalization here can cause mismatches for mixed-case keys and duplicate entries. Align this lookup with the canonical session-key normalization used by the session store APIs.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/auto-reply/reply/dispatch-from-config.ts
Line: 68:72

Comment:
**Inconsistent session key lookup**

This file still does `store[sessionKey.toLowerCase()] ?? store[sessionKey]` when reading the session store, but elsewhere the PR notes a “session-key normalization touch-up”. If other code paths now normalize differently (e.g., via a shared helper), leaving this ad-hoc normalization here can cause mismatches for mixed-case keys and duplicate entries. Align this lookup with the canonical session-key normalization used by the session store APIs.


How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@vincentkoc
Copy link
Contributor Author

@greptileai fixed sendTextChunks so it now mirrors the Signal chunk behavior, patching the last issue you raised. PR should be ready to merge, can you update the PR score please?

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

src/infra/outbound/message.ts
Missing session attribution

In sendMessage(), the delivery call only forwards a session key when mirroring is enabled. Since calls without mirroring are allowed, outbound message hooks invoked from this path will always receive an undefined session key in their context, preventing reliable session attribution for those sends.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/infra/outbound/message.ts
Line: 162:165

Comment:
**Missing session attribution**

In `sendMessage()`, the delivery call only forwards a session key when mirroring is enabled. Since calls without mirroring are allowed, outbound message hooks invoked from this path will always receive an undefined session key in their context, preventing reliable session attribution for those sends.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 9, 2026

Additional Comments (1)

src/infra/outbound/message.ts
Session context not propagated

In sendMessage(), deliverOutboundPayloads is called with sessionKey sourced from params.mirror?.sessionKey (see src/infra/outbound/message.ts:162-168). This makes outbound hooks receive a session key only when mirroring is enabled, rather than from the actual send/session context used by normal agent/chat flows. As a result, many message_sending / message_sent events will have missing session attribution even after this PR.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/infra/outbound/message.ts
Line: 162:168

Comment:
**Session context not propagated**

In `sendMessage()`, `deliverOutboundPayloads` is called with `sessionKey` sourced from `params.mirror?.sessionKey` (see `src/infra/outbound/message.ts:162-168`). This makes outbound hooks receive a session key only when mirroring is enabled, rather than from the actual send/session context used by normal agent/chat flows. As a result, many `message_sending` / `message_sent` events will have missing session attribution even after this PR.

How can I resolve this? If you propose a fix, please make it concise.

@vincentkoc vincentkoc force-pushed the vincentkoc-code/hooks-message-lifecycle branch from 5ec6821 to 60002ac Compare February 14, 2026 16:55
dashed added a commit to dashed/openclaw that referenced this pull request Feb 14, 2026
When a message_sending plugin hook cancels outbound delivery by
returning { cancel: true }, the message_sent hook was silently
skipped. Plugins tracking delivery outcomes (audit logging,
analytics) had no visibility into cancelled sends.

Fire message_sent with { success: false, error: "canceled by
message_sending hook" } before the continue, following the pattern
established in PR openclaw#12584.

Closes openclaw#16596
dashed added a commit to dashed/openclaw that referenced this pull request Feb 17, 2026
When a message_sending plugin hook cancels outbound delivery by
returning { cancel: true }, the message_sent hook was silently
skipped. Plugins tracking delivery outcomes (audit logging,
analytics) had no visibility into cancelled sends.

Fire message_sent with { success: false, error: "canceled by
message_sending hook" } before the continue, following the pattern
established in PR openclaw#12584.

Closes openclaw#16596
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Improvements or additions to documentation gateway Gateway runtime size: M

Projects

None yet

1 participant

Comments