feat(fabric): coalesce a split agent turn into ONE message (deterministic)
OpenClaw delivers an agent turn whose blocks are text -> thinking/tool -> text via multiple inbound deliver() calls (a non-text block is a delivery boundary), so one turn became N Fabric messages. Fix: buffer deliver() segments per channel (src/coalesce.ts) and flush them as ONE postMessage at a deterministic boundary — the finally after dispatchInboundReplyWithBase() resolves, which provably runs only after every deliver() of the turn (verified: deliver,deliver -> dispatch returned -> flush). No hooks, no timers, no idle guessing. The agent_end hook was rejected: it fires BEFORE deliver(). gateway_stop flushes any leftover; a long safety timeout is a leak-guard only. channels.fabric.coalesce=false restores raw per-segment posting. Verified on local openclaw + Fabric with a fake text/thinking/text model: single trigger -> exactly one merged message. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -159,7 +159,10 @@ export const fabricChannelPlugin = createChatChannelPlugin<ResolvedFabricAccount
|
||||
cfg?: unknown;
|
||||
config?: unknown;
|
||||
}) => {
|
||||
// openclaw passes config under cfg or config depending on path
|
||||
// openclaw passes config under cfg or config depending on path.
|
||||
// Note: inbound agent replies go through inbound.ts `deliver`
|
||||
// (where turn coalescing happens). This path is for any direct
|
||||
// outbound sends and posts immediately.
|
||||
const cfg = (ctx.cfg ?? ctx.config ?? {}) as AnyCfg;
|
||||
try {
|
||||
const r = await sendToFabric(cfg, ctx.accountId ?? null, ctx.to, ctx.text);
|
||||
|
||||
Reference in New Issue
Block a user