From 92945b777d6912774565ef483e7da9bf18ab7885 Mon Sep 17 00:00:00 2001 From: hzhang Date: Mon, 18 May 2026 09:18:20 +0100 Subject: [PATCH] feat(fabric): dm channels deliver any non-self message (no wakeup gate) inbound: FabricMessage gains xType; the wakeup gate is bypassed when xType==='dm' (self messages are already filtered upstream), so a 1:1 dm always reaches the model regardless of wakeup metadata. Co-Authored-By: Claude Opus 4.7 (1M context) --- dist/fabric/src/inbound.js | 6 +++++- src/inbound.ts | 9 ++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/dist/fabric/src/inbound.js b/dist/fabric/src/inbound.js index 54df8b2..570b04e 100644 --- a/dist/fabric/src/inbound.js +++ b/dist/fabric/src/inbound.js @@ -201,7 +201,11 @@ export class FabricInbound { // the woken speaker emits a normal message or /no-reply). We still // record the message into the agent's session so it has the full // channel conversation as context whenever it IS later woken. - if (m.wakeup !== true) { + // + // Exception: dm channels are 1:1 — there is no turn/wakeup gating; + // any message that isn't the agent's own (already filtered above) is + // always delivered to the model. + if (m.xType !== 'dm' && m.wakeup !== true) { const ctxPayload = core.channel.reply.finalizeInboundContext(baseCtx); await core.channel.session.recordInboundSession({ storePath, diff --git a/src/inbound.ts b/src/inbound.ts index efce9e4..435fab1 100644 --- a/src/inbound.ts +++ b/src/inbound.ts @@ -44,6 +44,9 @@ type FabricMessage = { channelId?: string; attachments?: FabricAttachment[]; wakeup?: boolean; + // x-type of the channel (sent on message.created). 'dm' bypasses the + // wakeup gate: any message that isn't the agent's own is delivered. + xType?: string; }; export class FabricInbound { @@ -252,7 +255,11 @@ export class FabricInbound { // the woken speaker emits a normal message or /no-reply). We still // record the message into the agent's session so it has the full // channel conversation as context whenever it IS later woken. - if (m.wakeup !== true) { + // + // Exception: dm channels are 1:1 — there is no turn/wakeup gating; + // any message that isn't the agent's own (already filtered above) is + // always delivered to the model. + if (m.xType !== 'dm' && m.wakeup !== true) { const ctxPayload = core.channel.reply.finalizeInboundContext(baseCtx); await core.channel.session.recordInboundSession({ storePath,