22summary : " Design plan for the unified durable message receive, send, preview, edit, and streaming lifecycle"
33read_when :
44 - Refactoring channel send or receive behavior
5- - Changing channel turn , reply dispatch, outbound queue, preview streaming, or plugin SDK message APIs
5+ - Changing channel inbound , reply dispatch, outbound queue, preview streaming, or plugin SDK message APIs
66 - Designing a new channel plugin that needs durable sends, receipts, previews, edits, or retries
77title : " Message lifecycle refactor"
88---
99
10- This page is the target design for replacing scattered channel turn , reply
10+ This page is the target design for replacing scattered channel inbound , reply
1111dispatch, preview streaming, and outbound delivery helpers with one durable
1212message lifecycle.
1313
@@ -20,14 +20,14 @@ The short version:
2020 commit, fail.
2121- Receiving must be context based too: normalize, dedupe, route, record,
2222 dispatch, platform ack, fail.
23- - The public plugin SDK should collapse to one small channel-message surface.
23+ - The public plugin SDK should collapse to one small channel-outbound surface.
2424
2525## Problems
2626
2727The current channel stack grew from several valid local needs:
2828
29- - Simple inbound adapters use ` runtime.channel.turn .run ` .
30- - Rich adapters use ` runtime.channel.turn.runPrepared ` .
29+ - Simple inbound adapters use ` runtime.channel.inbound .run ` .
30+ - Rich adapters use ` runtime.channel.inbound.runPreparedReply ` .
3131- Legacy helpers use ` dispatchInboundReplyWithBase ` ,
3232 ` recordInboundSessionAndDispatchReply ` , reply payload helpers, reply chunking,
3333 reply references, and outbound runtime helpers.
@@ -67,7 +67,7 @@ non-durable policy.
6767- Shared preview, edit, stream, finalization, retry, recovery, and receipt
6868 semantics.
6969- A small plugin SDK surface that third-party plugins can learn and maintain.
70- - Compatibility for existing ` channel.turn ` callers during migration.
70+ - Compatibility for existing inbound reply compatibility callers during migration.
7171- Clear extension points for new channel capabilities.
7272- No platform-specific branches in core.
7373- No token-delta channel messages. Channel streaming remains message preview,
@@ -77,7 +77,7 @@ non-durable policy.
7777
7878## Non goals
7979
80- - Do not remove ` runtime. channel.turn.* ` in the first phase.
80+ - Do not force every existing channel onto durable message delivery in the first phase.
8181- Do not force every channel into the same native transport behavior.
8282- Do not teach core Telegram topics, Slack native streams, Matrix redactions,
8383 Feishu cards, QQ voice, or Teams activities.
@@ -557,7 +557,7 @@ This should cover current behavior:
557557The public SDK target should be one subpath:
558558
559559``` typescript
560- import { defineChannelMessageAdapter } from " openclaw/plugin-sdk/channel-message " ;
560+ import { defineChannelMessageAdapter } from " openclaw/plugin-sdk/channel-outbound " ;
561561```
562562
563563Target shape:
@@ -670,22 +670,22 @@ should not need them.
670670
671671Bundled plugins may keep internal helper imports through reserved runtime
672672subpaths while migrating. Public docs should steer plugin authors to
673- ` plugin-sdk/channel-message ` once it exists.
673+ ` plugin-sdk/channel-outbound ` once it exists.
674674
675- ## Relationship to channel turn
675+ ## Relationship to channel inbound
676676
677- ` runtime.channel.turn .* ` should stay during migration.
677+ ` runtime.channel.inbound .* ` is the runtime bridge during migration.
678678
679679It should become a compatibility adapter:
680680
681681``` text
682- channel.turn .run
682+ channel.inbound .run
683683 -> messages.receive context
684684 -> session dispatch
685685 -> messages.send context for visible output
686686```
687687
688- ` channel.turn.runPrepared ` should also remain initially:
688+ ` channel.inbound.runPreparedReply ` should also remain initially:
689689
690690``` text
691691channel-owned dispatcher
@@ -694,10 +694,8 @@ channel-owned dispatcher
694694 -> messages.send for final delivery
695695```
696696
697- After all bundled plugins and known third-party compatibility paths are bridged,
698- ` channel.turn ` can be deprecated. It should not be removed until there is a
699- published SDK migration path and contract tests proving old plugins still work
700- or fail with a clear version error.
697+ The old ` channel.turn ` runtime surface remains a deprecated alias only. New code
698+ uses inbound/message nouns.
701699
702700## Compatibility guardrails
703701
@@ -706,10 +704,10 @@ existing delivery callback has side effects beyond "send this payload".
706704
707705Legacy entry points are non-durable by default:
708706
709- - ` channel.turn .run ` and ` dispatchAssembledChannelTurn ` use the channel's
707+ - ` channel.inbound .run ` and ` dispatchChannelInboundReply ` use the channel's
710708 delivery callback unless that channel explicitly supplies an audited durable
711709 policy/options object.
712- - ` channel.turn.runPrepared ` stays channel-owned until the prepared dispatcher
710+ - ` channel.inbound.runPreparedReply ` stays channel-owned until the prepared dispatcher
713711 explicitly calls the send context.
714712- Public compatibility helpers such as ` recordInboundSessionAndDispatchReply ` ,
715713 ` dispatchInboundReplyWithBase ` , and direct-DM helpers never inject generic
@@ -902,17 +900,17 @@ Core policy:
902900- Make ` deliverOutboundPayloads ` call ` messages.send ` .
903901- Make final-send durability the default and fail closed when the durable intent
904902 cannot be written in the new message lifecycle, after the adapter declares
905- replay safety. Existing channel-turn and SDK compatibility paths remain
903+ replay safety. Existing inbound runner and SDK compatibility paths remain
906904 direct-send by default during this phase.
907905- Record receipts consistently.
908906- Return receipts and delivery results to the original dispatcher caller instead
909907 of treating durable send as a terminal side effect.
910908- Persist message origin through durable send intents so recovery, replay, and
911909 chunked sends preserve OpenClaw operational provenance.
912910
913- ### Phase 3: Channel Turn Bridge
911+ ### Phase 3: Channel Inbound Bridge
914912
915- - Reimplement ` channel.turn .run ` and ` dispatchAssembledChannelTurn ` on top of
913+ - Reimplement ` channel.inbound .run ` and ` dispatchChannelInboundReply ` on top of
916914 ` messages.receive ` and ` messages.send ` .
917915- Keep current fact types stable.
918916- Keep legacy behavior by default. An assembled-turn channel becomes durable
@@ -950,12 +948,12 @@ Core policy:
950948
951949### Phase 6: Public SDK
952950
953- - Add ` openclaw/plugin-sdk/channel-message ` .
951+ - Add ` openclaw/plugin-sdk/channel-outbound ` .
954952- Document it as the preferred channel plugin API.
955953- Update package exports, entrypoint inventory, generated API baselines, and
956954 plugin SDK docs.
957955- Include ` MessageOrigin ` , origin encode/decode hooks, and the shared
958- ` shouldDropOpenClawEcho ` predicate in the channel-message SDK surface.
956+ ` shouldDropOpenClawEcho ` predicate in the channel-outbound SDK surface.
959957- Keep compatibility wrappers for old subpaths.
960958- Mark reply-named SDK helpers as deprecated in docs after bundled plugins are
961959 migrated.
@@ -976,9 +974,9 @@ Move all non-reply outbound producers onto `messages.send`:
976974This is where the model stops being "agent replies" and becomes "OpenClaw sends
977975messages".
978976
979- ### Phase 8: Deprecate Turn
977+ ### Phase 8: Remove Turn-Named Compatibility
980978
981- - Keep ` channel.turn ` as a wrapper for at least one compatibility window.
979+ - Keep inbound/message-named wrappers as the compatibility window.
982980- Publish migration notes.
983981- Run plugin SDK compatibility tests against old imports.
984982- Remove or hide old internal helpers only after no bundled plugin needs them
@@ -1002,10 +1000,10 @@ Unit tests:
10021000
10031001Integration tests:
10041002
1005- - ` channel.turn .run ` simple adapter still records and sends.
1003+ - ` channel.inbound .run ` simple adapter still records and sends.
10061004- Legacy assembled-event delivery does not become durable unless the channel
10071005 explicitly opts in.
1008- - ` channel.turn.runPrepared ` bridge still records and finalizes.
1006+ - ` channel.inbound.runPreparedReply ` bridge still records and finalizes.
10091007- Public compatibility helpers call caller-owned delivery callbacks by default
10101008 and do not generic-send before those callbacks.
10111009- Durable fallback delivery replays the whole projected payload array after
@@ -1075,7 +1073,7 @@ Validation:
10751073- Whether durable live preview state should be stored in the same queue record
10761074 as the final send intent or in a sibling live-state store.
10771075- How long compatibility wrappers stay documented after
1078- ` plugin-sdk/channel-message ` ships.
1076+ ` plugin-sdk/channel-outbound ` ships.
10791077- Whether third-party plugins should implement receive adapters directly or only
10801078 provide normalize/send/live hooks through ` defineChannelMessageAdapter ` .
10811079- Which receipt fields are safe to expose in public SDK versus internal runtime
@@ -1094,15 +1092,15 @@ Validation:
10941092 documented compatibility wrapper.
10951093- Every preview/edit/stream channel uses ` messages.live ` for draft state and
10961094 finalization.
1097- - ` channel.turn ` is only a wrapper.
1095+ - ` channel.inbound ` is only a wrapper.
10981096- Reply-named SDK helpers are compatibility exports, not the recommended path.
10991097- Durable recovery can replay pending final sends after restart without losing
11001098 the final response or duplicating already committed sends; sends whose
11011099 platform outcome is unknown are reconciled before replay or documented as
11021100 at-least-once for that adapter.
11031101- Durable final sends fail closed when the durable intent cannot be written,
11041102 unless a caller explicitly selected a documented non-durable mode.
1105- - Legacy channel-turn and SDK compatibility helpers default to direct
1103+ - Legacy SDK compatibility helpers default to direct
11061104 channel-owned delivery; generic durable send is explicit opt-in only.
11071105- Receipts preserve all platform message ids for multi-part deliveries and a
11081106 primary id for threading/edit convenience.
@@ -1125,4 +1123,4 @@ Validation:
11251123- [ Streaming and chunking] ( /concepts/streaming )
11261124- [ Progress drafts] ( /concepts/progress-drafts )
11271125- [ Retry policy] ( /concepts/retry )
1128- - [ Channel turn kernel ] ( /plugins/sdk-channel-turn )
1126+ - [ Channel inbound API ] ( /plugins/sdk-channel-inbound )
0 commit comments