diff --git a/src/gateway/server-restart-sentinel.ts b/src/gateway/server-restart-sentinel.ts index e536193accd..454657d188d 100644 --- a/src/gateway/server-restart-sentinel.ts +++ b/src/gateway/server-restart-sentinel.ts @@ -76,13 +76,22 @@ export async function scheduleRestartSentinelWake(_params: { deps: CliDeps }) { sessionThreadId ?? (origin?.threadId != null ? String(origin.threadId) : undefined); + // Slack uses replyToId (thread_ts) for threading, not threadId. + // The reply path does this mapping but deliverOutboundPayloads does not, + // so we must convert here to ensure post-restart notifications land in + // the originating Slack thread. See #17716. + const isSlack = channel === "slack"; + const replyToId = isSlack && threadId != null && threadId !== "" ? String(threadId) : undefined; + const resolvedThreadId = isSlack ? undefined : threadId; + try { await deliverOutboundPayloads({ cfg, channel, to: resolved.to, accountId: origin?.accountId, - threadId, + replyToId, + threadId: resolvedThreadId, payloads: [{ text: message }], agentId: resolveSessionAgentId({ sessionKey, config: cfg }), bestEffort: true,