mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:50:43 +00:00
fix(telegram): require authorized abort supersede
This commit is contained in:
@@ -2780,6 +2780,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
Body: "abort",
|
||||
RawBody: "abort",
|
||||
CommandBody: "abort",
|
||||
CommandAuthorized: true,
|
||||
} as never,
|
||||
}),
|
||||
});
|
||||
@@ -2863,6 +2864,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
Body: "abort",
|
||||
RawBody: "abort",
|
||||
CommandBody: "abort",
|
||||
CommandAuthorized: true,
|
||||
} as never,
|
||||
}),
|
||||
});
|
||||
@@ -2933,6 +2935,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
Body: "abort",
|
||||
RawBody: "abort",
|
||||
CommandBody: "abort",
|
||||
CommandAuthorized: true,
|
||||
} as never,
|
||||
}),
|
||||
});
|
||||
@@ -3038,6 +3041,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
Body: "abort",
|
||||
RawBody: "abort",
|
||||
CommandBody: "abort",
|
||||
CommandAuthorized: true,
|
||||
} as never,
|
||||
}),
|
||||
});
|
||||
@@ -3130,6 +3134,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
Body: "abort",
|
||||
RawBody: "abort",
|
||||
CommandBody: "abort",
|
||||
CommandAuthorized: true,
|
||||
} as never,
|
||||
}),
|
||||
});
|
||||
@@ -3219,6 +3224,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
Body: "abort",
|
||||
RawBody: "abort",
|
||||
CommandBody: "abort",
|
||||
CommandAuthorized: true,
|
||||
} as never,
|
||||
}),
|
||||
bot,
|
||||
@@ -3299,6 +3305,7 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
Body: "abort",
|
||||
RawBody: "abort",
|
||||
CommandBody: "abort",
|
||||
CommandAuthorized: true,
|
||||
} as never,
|
||||
}),
|
||||
});
|
||||
@@ -3439,6 +3446,89 @@ describe("dispatchTelegramMessage draft streaming", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("does not supersede the same session for unauthorized abort-looking commands", async () => {
|
||||
let releaseFirstFinal!: () => void;
|
||||
const firstFinalGate = new Promise<void>((resolve) => {
|
||||
releaseFirstFinal = resolve;
|
||||
});
|
||||
let resolvePreviewVisible!: () => void;
|
||||
const previewVisible = new Promise<void>((resolve) => {
|
||||
resolvePreviewVisible = resolve;
|
||||
});
|
||||
|
||||
const firstAnswerDraft = createTestDraftStream({
|
||||
messageId: 1001,
|
||||
onUpdate: (text) => {
|
||||
if (text === "Old reply partial") {
|
||||
resolvePreviewVisible();
|
||||
}
|
||||
},
|
||||
});
|
||||
const firstReasoningDraft = createDraftStream();
|
||||
const unauthorizedAnswerDraft = createDraftStream();
|
||||
const unauthorizedReasoningDraft = createDraftStream();
|
||||
createTelegramDraftStream
|
||||
.mockImplementationOnce(() => firstAnswerDraft)
|
||||
.mockImplementationOnce(() => firstReasoningDraft)
|
||||
.mockImplementationOnce(() => unauthorizedAnswerDraft)
|
||||
.mockImplementationOnce(() => unauthorizedReasoningDraft);
|
||||
dispatchReplyWithBufferedBlockDispatcher
|
||||
.mockImplementationOnce(async ({ dispatcherOptions, replyOptions }) => {
|
||||
await replyOptions?.onPartialReply?.({ text: "Old reply partial" });
|
||||
await firstFinalGate;
|
||||
await dispatcherOptions.deliver({ text: "Old reply final" }, { kind: "final" });
|
||||
return { queuedFinal: true };
|
||||
})
|
||||
.mockImplementationOnce(async ({ dispatcherOptions }) => {
|
||||
await dispatcherOptions.deliver({ text: "Unauthorized stop" }, { kind: "final" });
|
||||
return { queuedFinal: true };
|
||||
});
|
||||
deliverReplies.mockResolvedValue({ delivered: true });
|
||||
editMessageTelegram.mockResolvedValue({ ok: true, chatId: "123", messageId: "1001" });
|
||||
|
||||
const firstPromise = dispatchWithContext({
|
||||
context: createContext({
|
||||
ctxPayload: {
|
||||
SessionKey: "s1",
|
||||
Body: "earlier request",
|
||||
RawBody: "earlier request",
|
||||
} as never,
|
||||
}),
|
||||
});
|
||||
|
||||
await previewVisible;
|
||||
|
||||
const unauthorizedPromise = dispatchWithContext({
|
||||
context: createContext({
|
||||
ctxPayload: {
|
||||
SessionKey: "s1",
|
||||
Body: "/stop",
|
||||
RawBody: "/stop",
|
||||
CommandBody: "/stop",
|
||||
CommandAuthorized: false,
|
||||
} as never,
|
||||
}),
|
||||
});
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(deliverReplies).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
replies: [{ text: "Unauthorized stop" }],
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
releaseFirstFinal();
|
||||
await Promise.all([firstPromise, unauthorizedPromise]);
|
||||
|
||||
expect(editMessageTelegram).toHaveBeenCalledWith(
|
||||
123,
|
||||
1001,
|
||||
"Old reply final",
|
||||
expect.any(Object),
|
||||
);
|
||||
});
|
||||
|
||||
it("uses resolved DM config for auto-topic-label overrides", async () => {
|
||||
dispatchReplyWithBufferedBlockDispatcher.mockResolvedValue({ queuedFinal: true });
|
||||
loadSessionStore.mockReturnValue({ s1: {} });
|
||||
|
||||
@@ -475,12 +475,13 @@ export const dispatchTelegramMessage = async ({
|
||||
: undefined;
|
||||
|
||||
const chunkMode = resolveChunkMode(cfg, "telegram", route.accountId);
|
||||
const shouldSupersedeAbortFence =
|
||||
ctxPayload.CommandAuthorized &&
|
||||
isAbortRequestText(ctxPayload.CommandBody ?? ctxPayload.RawBody ?? ctxPayload.Body ?? "");
|
||||
|
||||
abortFenceGeneration = beginTelegramAbortFence({
|
||||
key: dispatchFenceKey,
|
||||
supersede: isAbortRequestText(
|
||||
ctxPayload.CommandBody ?? ctxPayload.RawBody ?? ctxPayload.Body ?? "",
|
||||
),
|
||||
supersede: shouldSupersedeAbortFence,
|
||||
});
|
||||
|
||||
const replyQuoteText =
|
||||
|
||||
Reference in New Issue
Block a user