





















@@ -26,6 +26,8 @@ const {
2626 maybePersistResolvedTelegramTarget,
2727 probeVideoDimensions,
2828} = getTelegramSendTestMocks();
29+const telegramSendModule = await importTelegramSendModule();
30+const { resetLogger, setLoggerOverride } = await import("openclaw/plugin-sdk/runtime-env");
2931const {
3032 buildInlineKeyboard,
3133 createForumTopicTelegram,
@@ -40,7 +42,7 @@ const {
4042 sendPollTelegram,
4143 sendStickerTelegram,
4244 unpinMessageTelegram,
43-} = await importTelegramSendModule();
45+} = telegramSendModule;
44464547const TELEGRAM_TEST_CFG = {};
4648@@ -163,6 +165,26 @@ function expectPersistedTarget(fields: Record<string, unknown>): void {
163165}
164166}
165167168+let logCaptureCounter = 0;
169+170+function captureInfoLogs(): string {
171+logCaptureCounter += 1;
172+const logFile = `/tmp/openclaw-telegram-send-log-${process.pid}-${logCaptureCounter}.jsonl`;
173+fs.rmSync(logFile, { force: true });
174+setLoggerOverride({ level: "info", consoleLevel: "silent", file: logFile });
175+return logFile;
176+}
177+178+function capturedLogText(logFile: string): string {
179+return fs.existsSync(logFile) ? fs.readFileSync(logFile, "utf8") : "";
180+}
181+182+afterEach(() => {
183+setLoggerOverride(null);
184+resetLogger();
185+vi.restoreAllMocks();
186+});
187+166188describe("sent-message-cache", () => {
167189afterEach(() => {
168190vi.useRealTimers();
@@ -1996,7 +2018,151 @@ describe("sendMessageTelegram", () => {
19962018});
19972019});
199820202021+it("logs successful outbound text delivery without the message body", async () => {
2022+const logFile = captureInfoLogs();
2023+const chatId = "-1001234567890";
2024+const body = "incident reply body should stay private";
2025+const sendMessage = vi.fn().mockResolvedValue({
2026+message_id: 321,
2027+chat: { id: chatId },
2028+});
2029+const api = { sendMessage } as unknown as {
2030+sendMessage: typeof sendMessage;
2031+};
2032+2033+await sendMessageTelegram(`telegram:group:${chatId}:topic:271`, body, {
2034+cfg: TELEGRAM_TEST_CFG,
2035+token: "tok",
2036+accountId: "ops",
2037+ api,
2038+replyToMessageId: 123,
2039+silent: true,
2040+});
2041+2042+const logs = capturedLogText(logFile);
2043+expect(logs).toContain("outbound send ok");
2044+expect(logs).toContain("accountId=ops");
2045+expect(logs).toContain(`chatId=${chatId}`);
2046+expect(logs).toContain("messageId=321");
2047+expect(logs).toContain("operation=sendMessage");
2048+expect(logs).toContain("threadId=271");
2049+expect(logs).toContain("replyToMessageId=123");
2050+expect(logs).toContain("silent=true");
2051+expect(logs).toContain("chunkCount=1");
2052+expect(logs).not.toContain(body);
2053+});
2054+2055+it("logs threadless outbound text delivery after missing-thread fallback", async () => {
2056+const logFile = captureInfoLogs();
2057+const chatId = "-1001234567890";
2058+const body = "fallback reply body should stay private";
2059+const threadErr = new Error("400: Bad Request: message thread not found");
2060+const sendMessage = vi
2061+.fn()
2062+.mockRejectedValueOnce(threadErr)
2063+.mockResolvedValueOnce({
2064+message_id: 322,
2065+chat: { id: chatId },
2066+});
2067+const api = { sendMessage } as unknown as {
2068+sendMessage: typeof sendMessage;
2069+};
2070+2071+await sendMessageTelegram(`telegram:group:${chatId}:topic:271`, body, {
2072+cfg: TELEGRAM_TEST_CFG,
2073+token: "tok",
2074+accountId: "ops",
2075+ api,
2076+});
2077+2078+expect(sendMessage).toHaveBeenNthCalledWith(1, chatId, body, {
2079+parse_mode: "HTML",
2080+message_thread_id: 271,
2081+});
2082+expect(sendMessage).toHaveBeenNthCalledWith(2, chatId, body, {
2083+parse_mode: "HTML",
2084+});
2085+const logs = capturedLogText(logFile);
2086+expect(logs).toContain("outbound send ok");
2087+expect(logs).toContain("messageId=322");
2088+expect(logs).not.toContain("threadId=271");
2089+expect(logs).not.toContain(body);
2090+});
2091+2092+it("logs successful outbound media delivery without caption or media location", async () => {
2093+const logFile = captureInfoLogs();
2094+const chatId = "123";
2095+const caption = "private media caption";
2096+const mediaUrl = "https://example.com/private-photo.jpg";
2097+const fileName = "private-photo.jpg";
2098+const sendPhoto = vi.fn().mockResolvedValue({
2099+message_id: 654,
2100+chat: { id: chatId },
2101+});
2102+const api = { sendPhoto } as unknown as {
2103+sendPhoto: typeof sendPhoto;
2104+};
2105+2106+mockLoadedMedia({
2107+buffer: Buffer.from("fake-image"),
2108+contentType: "image/jpeg",
2109+ fileName,
2110+});
2111+2112+await sendMessageTelegram(chatId, caption, {
2113+cfg: TELEGRAM_TEST_CFG,
2114+token: "tok",
2115+accountId: "ops",
2116+ api,
2117+ mediaUrl,
2118+messageThreadId: 45,
2119+});
2120+2121+const logs = capturedLogText(logFile);
2122+expect(logs).toContain("outbound send ok");
2123+expect(logs).toContain("accountId=ops");
2124+expect(logs).toContain(`chatId=${chatId}`);
2125+expect(logs).toContain("messageId=654");
2126+expect(logs).toContain("operation=sendPhoto");
2127+expect(logs).toContain("deliveryKind=photo");
2128+expect(logs).toContain("threadId=45");
2129+expect(logs).not.toContain(caption);
2130+expect(logs).not.toContain(mediaUrl);
2131+expect(logs).not.toContain(fileName);
2132+});
2133+2134+it("does not log outbound success when a chunked text delivery fails mid-send", async () => {
2135+const logFile = captureInfoLogs();
2136+const chatId = "123";
2137+const body = "private chunked body ".repeat(260);
2138+const sendMessage = vi
2139+.fn()
2140+.mockResolvedValueOnce({
2141+message_id: 700,
2142+chat: { id: chatId },
2143+})
2144+.mockRejectedValueOnce(new Error("telegram send failed"));
2145+const api = { sendMessage } as unknown as {
2146+sendMessage: typeof sendMessage;
2147+};
2148+2149+await expect(
2150+sendMessageTelegram(chatId, body, {
2151+cfg: TELEGRAM_TEST_CFG,
2152+token: "tok",
2153+accountId: "ops",
2154+ api,
2155+}),
2156+).rejects.toThrow(/telegram send failed/);
2157+2158+expect(sendMessage).toHaveBeenCalledTimes(2);
2159+const logs = capturedLogText(logFile);
2160+expect(logs).not.toContain("outbound send ok");
2161+expect(logs).not.toContain(body);
2162+});
2163+19992164it("retries media sends without message_thread_id when thread is missing", async () => {
2165+const logFile = captureInfoLogs();
20002166const chatId = "-100123";
20012167const threadErr = new Error("400: Bad Request: message thread not found");
20022168const sendPhoto = vi
@@ -2044,6 +2210,10 @@ describe("sendMessageTelegram", () => {
20442210},
20452211);
20462212expect(res.messageId).toBe("59");
2213+const logs = capturedLogText(logFile);
2214+expect(logs).toContain("outbound send ok");
2215+expect(logs).toContain("messageId=59");
2216+expect(logs).not.toContain("threadId=271");
20472217});
2048221820492219it("defaults outbound media uploads to 100MB", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。