#5525: Add plugin hook to resolve canonical RoomKey for session identity and FIFO routing
docs
channel: telegram
## Summary
This PR introduces a small, backward-compatible core hook that allows plugins to deterministically influence the canonical conversation identity ("RoomKey") used by OpenClaw for:
- session/transcript selection
- FIFO queue lane selection (ordering)
By default, behavior is unchanged.
## Motivation
OpenClaw’s pipeline already relies on a stable concept of "room/session identity" that drives both history selection and per-session serialization. Today, there is no first-class extension point for plugins to participate in that identity derivation, which forces plugins that need deterministic isolation to either patch channel internals (fragile) or rely on prompt-only scoping (best-effort).
This PR adds the minimal missing abstraction: a hook that lets plugins resolve a canonical RoomKey early in inbound context construction, before any session lookup or queueing occurs.
## Design goals
- Minimal surface area: one hook, one return value
- Backward compatible: default path unchanged
- One invariant: the same key is used for transcript identity and FIFO lane ordering
- Channel-agnostic core API (no "projects" concept in core)
## Proposed API
New hook: `resolve_room_key`
- Called after core computes the default session/room key.
- Plugins may return `{ roomKey }` to override the canonical key; returning `undefined` means no change.
Invariant:
- The returned `roomKey` is used as both the session identity key and the FIFO lane key.
## Implementation notes
- Adds helper: `resolveCanonicalRoomKey()` in `src/routing/room-key.ts` which calls the global hook runner if hooks are registered.
- Telegram inbound context builder calls `resolveCanonicalRoomKey()` after computing the base key.
- Plugin command context includes optional message metadata (`messageId`, `threadId`, `chatId`) to support deterministic semantics tied to monotonic message ids.
## Tests
- Unit test asserts:
- no hook => roomKey unchanged
- hook override => roomKey changes and the derived session lane uses the same key
## Non-goals
- No new user-facing features
- No Telegram-specific behavior beyond supplying normalized metadata into the hook
- No changes to default session semantics
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR adds a new plugin hook (`resolve_room_key`) plus a helper (`resolveCanonicalRoomKey`) to allow plugins to deterministically override the canonical “room key” used for session/transcript identity and FIFO lane ordering. Telegram inbound context now calls this helper after computing the base + thread session key, and plugin command execution gets optional message metadata (messageId/threadId/chatId) to support deterministic per-message semantics. A small unit test covers the default (no hook) and override paths.
Key risk areas are around conflict resolution when multiple plugins register the hook (priority semantics) and ensuring empty/whitespace keys can’t accidentally collapse session identity.
<h3>Confidence Score: 4/5</h3>
- This PR is likely safe to merge, but has a couple of edge-case correctness concerns around room-key resolution semantics.
- Changes are small and mostly additive, with a clear test for the hook override path. Main concerns are (1) `resolve_room_key` merge semantics currently allow lower-priority hooks to override higher-priority ones when multiple plugins return different values, and (2) the helper’s empty/whitespace handling could collapse the canonical key if bad input slips through.
- src/plugins/hooks.ts, src/routing/room-key.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#20858: fix(hooks): normalize hook addresses to canonical provider:kind:id ...
by davidrudduck · 2026-02-19
76.4%
#6405: feat(security): Add HTTP API security hooks for plugin scanning
by masterfung · 2026-02-01
75.4%
#17346: feat(hooks): add message_persist hook for all transcript messages
by clawee-vanguard · 2026-02-15
73.8%
#6853: fix: fire internal hooks on sessions.reset RPC (TUI/webchat /new)
by hamiltonchua · 2026-02-02
73.6%
#20541: fix(hooks): clear internal hooks before plugins register
by ramarnat · 2026-02-19
73.4%
#10680: docs: clarify api.on() vs api.registerHook() for plugin hooks
by yassinebkr · 2026-02-06
73.2%
#15571: feat: infrastructure foundation — hooks, model failover, sessions, ...
by tangcruz · 2026-02-13
73.2%
#9906: feat: wire message_sending hook in outbound delivery
by teempai · 2026-02-05
73.1%
#23019: fix(hooks): use globalThis singleton for internal hooks handlers Map
by karmafeast · 2026-02-21
72.9%
#8431: Hooks: add session-graphiti memory feed
by JorgeAlan · 2026-02-04
72.8%