fix(slack): clear assistant thread status after replies

This commit is contained in:
Peter Steinberger
2026-01-06 21:41:30 +01:00
parent 8ebc789d25
commit 84c8209158
6 changed files with 205 additions and 179 deletions

View File

@@ -17,8 +17,7 @@ import {
buildMentionRegexes,
normalizeMentionText,
} from "../auto-reply/reply/mentions.js";
import { createReplyDispatcher } from "../auto-reply/reply/reply-dispatcher.js";
import type { TypingController } from "../auto-reply/reply/typing.js";
import { createReplyDispatcherWithTyping } from "../auto-reply/reply/reply-dispatcher.js";
import { getReplyFromConfig } from "../auto-reply/reply.js";
import { HEARTBEAT_TOKEN, SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
import type { ReplyPayload } from "../auto-reply/types.js";
@@ -1161,72 +1160,70 @@ export async function monitorWebProvider(
const textLimit = resolveTextChunkLimit(cfg, "whatsapp");
let didLogHeartbeatStrip = false;
let didSendReply = false;
let typingController: TypingController | undefined;
const dispatcher = createReplyDispatcher({
responsePrefix: cfg.messages?.responsePrefix,
onHeartbeatStrip: () => {
if (!didLogHeartbeatStrip) {
didLogHeartbeatStrip = true;
logVerbose("Stripped stray HEARTBEAT_OK token from web reply");
}
},
deliver: async (payload, info) => {
await deliverWebReply({
replyResult: payload,
msg,
maxMediaBytes,
textLimit,
replyLogger,
connectionId,
// Tool + block updates are noisy; skip their log lines.
skipLog: info.kind !== "final",
});
didSendReply = true;
if (info.kind === "tool") {
rememberSentText(payload.text, { combinedBody: "" });
return;
}
const shouldLog =
info.kind === "final" && payload.text ? true : undefined;
rememberSentText(payload.text, {
combinedBody,
logVerboseMessage: shouldLog,
});
if (info.kind === "final") {
const fromDisplay =
msg.chatType === "group"
? conversationId
: (msg.from ?? "unknown");
const hasMedia = Boolean(
payload.mediaUrl || payload.mediaUrls?.length,
);
whatsappOutboundLog.info(
`Auto-replied to ${fromDisplay}${hasMedia ? " (media)" : ""}`,
);
if (shouldLogVerbose()) {
const preview =
payload.text != null ? elide(payload.text, 400) : "<media>";
whatsappOutboundLog.debug(
`Reply body: ${preview}${hasMedia ? " (media)" : ""}`,
);
const { dispatcher, replyOptions, markDispatchIdle } =
createReplyDispatcherWithTyping({
responsePrefix: cfg.messages?.responsePrefix,
onHeartbeatStrip: () => {
if (!didLogHeartbeatStrip) {
didLogHeartbeatStrip = true;
logVerbose("Stripped stray HEARTBEAT_OK token from web reply");
}
}
},
onIdle: () => {
typingController?.markDispatchIdle();
},
onError: (err, info) => {
const label =
info.kind === "tool"
? "tool update"
: info.kind === "block"
? "block update"
: "auto-reply";
whatsappOutboundLog.error(
`Failed sending web ${label} to ${msg.from ?? conversationId}: ${formatError(err)}`,
);
},
});
},
deliver: async (payload, info) => {
await deliverWebReply({
replyResult: payload,
msg,
maxMediaBytes,
textLimit,
replyLogger,
connectionId,
// Tool + block updates are noisy; skip their log lines.
skipLog: info.kind !== "final",
});
didSendReply = true;
if (info.kind === "tool") {
rememberSentText(payload.text, { combinedBody: "" });
return;
}
const shouldLog =
info.kind === "final" && payload.text ? true : undefined;
rememberSentText(payload.text, {
combinedBody,
logVerboseMessage: shouldLog,
});
if (info.kind === "final") {
const fromDisplay =
msg.chatType === "group"
? conversationId
: (msg.from ?? "unknown");
const hasMedia = Boolean(
payload.mediaUrl || payload.mediaUrls?.length,
);
whatsappOutboundLog.info(
`Auto-replied to ${fromDisplay}${hasMedia ? " (media)" : ""}`,
);
if (shouldLogVerbose()) {
const preview =
payload.text != null ? elide(payload.text, 400) : "<media>";
whatsappOutboundLog.debug(
`Reply body: ${preview}${hasMedia ? " (media)" : ""}`,
);
}
}
},
onError: (err, info) => {
const label =
info.kind === "tool"
? "tool update"
: info.kind === "block"
? "block update"
: "auto-reply";
whatsappOutboundLog.error(
`Failed sending web ${label} to ${msg.from ?? conversationId}: ${formatError(err)}`,
);
},
onReplyStart: msg.sendComposing,
});
const { queuedFinal } = await dispatchReplyFromConfig({
ctx: {
@@ -1258,14 +1255,9 @@ export async function monitorWebProvider(
cfg,
dispatcher,
replyResolver,
replyOptions: {
onReplyStart: msg.sendComposing,
onTypingController: (typing) => {
typingController = typing;
},
},
replyOptions,
});
typingController?.markDispatchIdle();
markDispatchIdle();
if (!queuedFinal) {
if (shouldClearGroupHistory && didSendReply) {
groupHistories.set(route.sessionKey, []);