Files
openclaw/docs/plugins/sdk-channel-outbound.md
Peter Steinberger 1507a9701b refactor: centralize inbound supplemental context
* refactor: centralize inbound supplemental context

* refactor: trim supplemental finalizer typing

* docs: clarify supplemental context projection

* refactor: move inbound finalization into core

* refactor: simplify channel inbound facts

* refactor: fold supplemental media into inbound finalizer

* refactor: migrate channel inbound callers to builder

* docs: mark inbound finalizer compat types deprecated

* refactor: wire runtime turn context builder

* refactor: replace channel turn runtime API

* fix: respect discord quote visibility

* fix: avoid deprecated line dispatch helper

* refactor: deprecate channel message SDK seams

* docs: trim channel outbound SDK page

* test: migrate irc inbound assertion

* refactor: deprecate outbound SDK facades

* refactor: deprecate channel helper SDK facades

* refactor: deprecate channel streaming SDK facade

* refactor: move direct dm helpers into inbound SDK

* chore: mark legacy test-utils SDK alias deprecated

* refactor: remove unused allow-from read helper

* refactor: route remaining channel dispatch through core

* refactor: enforce modern extension SDK imports

* test: give slow image root tests more time

* ci: support node fallback on windows

* fix: add transcripts tool display metadata

* refactor: trim legacy channel test seams

* fix: preserve channel compat after rebase

* fix: keep deprecated channel inbound aliases

* fix: preserve discord thread context visibility

* fix: clean final rebase conflicts

* fix: preserve channel message dispatch aliases

* fix: sync channel refactor after rebase

* fix: sync channel refactor after latest main

* fix: dedupe memory-core subagent mock

* test: align clickclack inbound dispatch assertions

* fix: sync plugin sdk api hash after rebase

* fix: sync channel refactor after latest main

* fix: sync plugin sdk api hash after rebase

* fix: sync plugin sdk api hash after latest main

* test: remove stale inbound context awaits
2026-05-27 09:26:06 +01:00

114 lines
3.7 KiB
Markdown

---
summary: "Outbound message lifecycle API for channel plugins: adapters, receipts, durable sends, live preview, and reply pipeline helpers"
title: "Channel outbound API"
read_when:
- You are building or refactoring a messaging channel plugin send path
- You need durable final reply delivery, receipts, live preview finalization, or receive acknowledgement policy
- You are migrating from channel-message, channel-message-runtime, or legacy reply dispatch helpers
---
Channel plugins should expose outbound message behavior from
`openclaw/plugin-sdk/channel-outbound`. Use
`openclaw/plugin-sdk/channel-inbound` for receive/context/dispatch orchestration.
Core owns queueing, durability, generic retry policy, hooks, receipts, and the
shared `message` tool. The plugin owns native send/edit/delete calls, target
normalization, platform threading, selected quotes, notification flags, account
state, and platform-specific side effects.
## Adapter
Most plugins define one `message` adapter:
```ts
import {
defineChannelMessageAdapter,
createMessageReceiptFromOutboundResults,
} from "openclaw/plugin-sdk/channel-outbound";
export const demoMessageAdapter = defineChannelMessageAdapter({
id: "demo",
durableFinal: {
capabilities: {
text: true,
replyTo: true,
thread: true,
messageSendingHooks: true,
},
},
send: {
text: async ({ cfg, to, text, accountId, replyToId, threadId, signal }) => {
const sent = await sendDemoMessage({
cfg,
to,
text,
accountId: accountId ?? undefined,
replyToId: replyToId ?? undefined,
threadId: threadId == null ? undefined : String(threadId),
signal,
});
return {
receipt: createMessageReceiptFromOutboundResults({
results: [{ channel: "demo", messageId: sent.id, conversationId: to }],
kind: "text",
threadId: threadId == null ? undefined : String(threadId),
replyToId: replyToId ?? undefined,
}),
};
},
},
});
```
Only declare capabilities the native transport actually preserves. Cover each
declared send, receipt, live-preview, and receive-ack capability with the
contract helpers exported from this subpath.
## Existing Outbound Adapters
If the channel already has a compatible `outbound` adapter, derive the message
adapter instead of duplicating send code:
```ts
import { createChannelMessageAdapterFromOutbound } from "openclaw/plugin-sdk/channel-outbound";
export const messageAdapter = createChannelMessageAdapterFromOutbound({
id: "demo",
outbound,
durableFinal: {
capabilities: {
text: true,
media: true,
},
},
});
```
## Durable Sends
Runtime send helpers also live on `channel-outbound`:
- `sendDurableMessageBatch(...)`
- `withDurableMessageSendContext(...)`
- `deliverInboundReplyWithMessageSendContext(...)`
- draft streaming/progress helpers such as `resolveChannelStreamingPreviewChunk(...)`
`sendDurableMessageBatch(...)` returns one explicit outcome:
- `sent`: at least one visible platform message was delivered.
- `suppressed`: no platform message should be treated as missing.
- `partial_failed`: at least one platform message was delivered before a later
payload or side effect failed.
- `failed`: no platform receipt was produced.
Use `payloadOutcomes` when a batch mixes sent, suppressed, and failed payloads.
Do not infer hook cancellation from an empty legacy direct-delivery result.
## Compatibility Dispatch
Inbound reply dispatch should be assembled through
`dispatchChannelInboundReply(...)` from `channel-inbound`. Keep platform
delivery in the delivery adapter; use `channel-outbound` for message adapters,
durable sends, receipts, live preview, and reply pipeline options.