mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-30 10:10:18 +00:00
fix(telegram): mark message_sent success only when delivery occurred
This commit is contained in:
@@ -33,6 +33,7 @@ const CAPTION_TOO_LONG_RE = /caption is too long/i;
|
||||
type DeliveryProgress = {
|
||||
hasReplied: boolean;
|
||||
hasDelivered: boolean;
|
||||
deliveredCount: number;
|
||||
};
|
||||
|
||||
type ChunkTextFn = (markdown: string) => ReturnType<typeof markdownToTelegramChunks>;
|
||||
@@ -85,6 +86,7 @@ function markReplyApplied(progress: DeliveryProgress, replyToId?: number): void
|
||||
|
||||
function markDelivered(progress: DeliveryProgress): void {
|
||||
progress.hasDelivered = true;
|
||||
progress.deliveredCount += 1;
|
||||
}
|
||||
|
||||
async function deliverTextReply(params: {
|
||||
@@ -445,6 +447,7 @@ export async function deliverReplies(params: {
|
||||
const progress: DeliveryProgress = {
|
||||
hasReplied: false,
|
||||
hasDelivered: false,
|
||||
deliveredCount: 0,
|
||||
};
|
||||
const hookRunner = getGlobalHookRunner();
|
||||
const hasMessageSendingHooks = hookRunner?.hasHooks("message_sending") ?? false;
|
||||
@@ -489,6 +492,7 @@ export async function deliverReplies(params: {
|
||||
const contentForSentHook = reply.text || "";
|
||||
|
||||
try {
|
||||
const deliveredCountBeforeReply = progress.deliveredCount;
|
||||
const replyToId =
|
||||
params.replyToMode === "off" ? undefined : resolveTelegramReplyId(reply.replyToId);
|
||||
const mediaList = reply.mediaUrls?.length
|
||||
@@ -537,11 +541,12 @@ export async function deliverReplies(params: {
|
||||
}
|
||||
|
||||
if (hasMessageSentHooks) {
|
||||
const deliveredThisReply = progress.deliveredCount > deliveredCountBeforeReply;
|
||||
void hookRunner?.runMessageSent(
|
||||
{
|
||||
to: params.chatId,
|
||||
content: contentForSentHook,
|
||||
success: true,
|
||||
success: deliveredThisReply,
|
||||
},
|
||||
{
|
||||
channelId: "telegram",
|
||||
|
||||
@@ -4,6 +4,11 @@ import type { RuntimeEnv } from "../../runtime.js";
|
||||
import { deliverReplies } from "./delivery.js";
|
||||
|
||||
const loadWebMedia = vi.fn();
|
||||
const messageHookRunner = vi.hoisted(() => ({
|
||||
hasHooks: vi.fn<(name: string) => boolean>(() => false),
|
||||
runMessageSending: vi.fn(),
|
||||
runMessageSent: vi.fn(),
|
||||
}));
|
||||
const baseDeliveryParams = {
|
||||
chatId: "123",
|
||||
token: "tok",
|
||||
@@ -22,6 +27,10 @@ vi.mock("../../web/media.js", () => ({
|
||||
loadWebMedia: (...args: unknown[]) => loadWebMedia(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../../plugins/hook-runner-global.js", () => ({
|
||||
getGlobalHookRunner: () => messageHookRunner,
|
||||
}));
|
||||
|
||||
vi.mock("grammy", () => ({
|
||||
InputFile: class {
|
||||
constructor(
|
||||
@@ -99,6 +108,10 @@ function createVoiceFailureHarness(params: {
|
||||
describe("deliverReplies", () => {
|
||||
beforeEach(() => {
|
||||
loadWebMedia.mockClear();
|
||||
messageHookRunner.hasHooks.mockReset();
|
||||
messageHookRunner.hasHooks.mockReturnValue(false);
|
||||
messageHookRunner.runMessageSending.mockReset();
|
||||
messageHookRunner.runMessageSent.mockReset();
|
||||
});
|
||||
|
||||
it("skips audioAsVoice-only payloads without logging an error", async () => {
|
||||
@@ -113,6 +126,29 @@ describe("deliverReplies", () => {
|
||||
expect(runtime.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reports message_sent success=false when hooks blank out a text-only reply", async () => {
|
||||
messageHookRunner.hasHooks.mockImplementation(
|
||||
(name: string) => name === "message_sending" || name === "message_sent",
|
||||
);
|
||||
messageHookRunner.runMessageSending.mockResolvedValue({ content: "" });
|
||||
|
||||
const runtime = createRuntime(false);
|
||||
const sendMessage = vi.fn();
|
||||
const bot = createBot({ sendMessage });
|
||||
|
||||
await deliverWith({
|
||||
replies: [{ text: "hello" }],
|
||||
runtime,
|
||||
bot,
|
||||
});
|
||||
|
||||
expect(sendMessage).not.toHaveBeenCalled();
|
||||
expect(messageHookRunner.runMessageSent).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ success: false, content: "" }),
|
||||
expect.objectContaining({ channelId: "telegram", conversationId: "123" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("invokes onVoiceRecording before sending a voice note", async () => {
|
||||
const events: string[] = [];
|
||||
const runtime = createRuntime(false);
|
||||
|
||||
Reference in New Issue
Block a user