mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-27 09:02:15 +00:00
fix(slack): preserve ack on pre-reply errors
This commit is contained in:
@@ -648,6 +648,57 @@ describe("monitorSlackProvider tool results", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("restores ack reaction when dispatch fails before any reply is delivered", async () => {
|
||||
replyMock.mockRejectedValue(new Error("boom"));
|
||||
slackTestState.config = {
|
||||
messages: {
|
||||
responsePrefix: "PFX",
|
||||
ackReaction: "👀",
|
||||
ackReactionScope: "group-mentions",
|
||||
removeAckAfterReply: true,
|
||||
statusReactions: {
|
||||
enabled: true,
|
||||
timing: { debounceMs: 0, doneHoldMs: 0, errorHoldMs: 0 },
|
||||
},
|
||||
},
|
||||
channels: {
|
||||
slack: {
|
||||
dm: { enabled: true, policy: "open", allowFrom: ["*"] },
|
||||
groupPolicy: "open",
|
||||
},
|
||||
},
|
||||
};
|
||||
const client = getSlackClient();
|
||||
if (!client) {
|
||||
throw new Error("Slack client not registered");
|
||||
}
|
||||
const conversations = client.conversations as {
|
||||
info: ReturnType<typeof vi.fn>;
|
||||
};
|
||||
conversations.info.mockResolvedValueOnce({
|
||||
channel: { name: "general", is_channel: true },
|
||||
});
|
||||
|
||||
await runSlackMessageOnce(monitorSlackProvider, {
|
||||
event: makeSlackMessageEvent({
|
||||
text: "<@bot-user> hello",
|
||||
ts: "456",
|
||||
channel_type: "channel",
|
||||
}),
|
||||
});
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
await flush();
|
||||
|
||||
expect(sendMock).not.toHaveBeenCalled();
|
||||
expect(reactMock.mock.calls.map(([args]) => String((args as { name: string }).name))).toEqual([
|
||||
"eyes",
|
||||
"scream",
|
||||
"eyes",
|
||||
"eyes",
|
||||
"scream",
|
||||
]);
|
||||
});
|
||||
|
||||
it("replies with pairing code when dmPolicy is pairing and no allowFrom is set", async () => {
|
||||
setPairingOnlyDirectMessages();
|
||||
|
||||
|
||||
@@ -348,6 +348,7 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
||||
let streamSession: SlackStreamSession | null = null;
|
||||
let streamFailed = false;
|
||||
let usedReplyThreadTs: string | undefined;
|
||||
let observedReplyDelivery = false;
|
||||
|
||||
const deliverNormally = async (payload: ReplyPayload, forcedThreadTs?: string): Promise<void> => {
|
||||
const replyThreadTs = forcedThreadTs ?? replyPlan.nextThreadTs();
|
||||
@@ -362,6 +363,7 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
||||
replyToMode: prepared.replyToMode,
|
||||
...(slackIdentity ? { identity: slackIdentity } : {}),
|
||||
});
|
||||
observedReplyDelivery = true;
|
||||
// Record the thread ts only after confirmed delivery success.
|
||||
if (replyThreadTs) {
|
||||
usedReplyThreadTs ??= replyThreadTs;
|
||||
@@ -399,6 +401,7 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
||||
teamId: ctx.teamId,
|
||||
userId: message.user,
|
||||
});
|
||||
observedReplyDelivery = true;
|
||||
usedReplyThreadTs ??= streamThreadTs;
|
||||
replyPlan.markSent();
|
||||
return;
|
||||
@@ -455,6 +458,7 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
||||
...(slackBlocks?.length ? { blocks: slackBlocks } : {}),
|
||||
},
|
||||
);
|
||||
observedReplyDelivery = true;
|
||||
return;
|
||||
} catch (err) {
|
||||
logVerbose(
|
||||
@@ -620,7 +624,8 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
||||
}
|
||||
}
|
||||
|
||||
const anyReplyDelivered = queuedFinal || (counts.block ?? 0) > 0 || (counts.final ?? 0) > 0;
|
||||
const anyReplyDelivered =
|
||||
observedReplyDelivery || queuedFinal || (counts.block ?? 0) > 0 || (counts.final ?? 0) > 0;
|
||||
|
||||
if (statusReactionsEnabled) {
|
||||
if (dispatchError) {
|
||||
@@ -628,7 +633,11 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
||||
if (ctx.removeAckAfterReply) {
|
||||
void (async () => {
|
||||
await sleep(statusReactionTiming.errorHoldMs);
|
||||
await statusReactions.clear();
|
||||
if (anyReplyDelivered) {
|
||||
await statusReactions.clear();
|
||||
return;
|
||||
}
|
||||
await statusReactions.restoreInitial();
|
||||
})();
|
||||
} else {
|
||||
void statusReactions.restoreInitial();
|
||||
|
||||
Reference in New Issue
Block a user