惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
GbyAI
GbyAI
Y
Y Combinator Blog
The GitHub Blog
The GitHub Blog
B
Blog
博客园 - 叶小钗
V
Visual Studio Blog
小众软件
小众软件
阮一峰的网络日志
阮一峰的网络日志
博客园 - 聂微东
S
SegmentFault 最新的问题
Engineering at Meta
Engineering at Meta
博客园 - Franky
V
V2EX
人人都是产品经理
人人都是产品经理
H
Hackread – Cybersecurity News, Data Breaches, AI and More
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
月光博客
月光博客
IT之家
IT之家
T
The Blog of Author Tim Ferriss
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
Check Point Blog
N
Netflix TechBlog - Medium
博客园 - 【当耐特】

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
Log Telegram outbound delivery success (#83247) · opencla...
clawsweeper · 2026-05-18 · via Recent Commits to openclaw:main

@@ -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");

2931

const {

3032

buildInlineKeyboard,

3133

createForumTopicTelegram,

@@ -40,7 +42,7 @@ const {

4042

sendPollTelegram,

4143

sendStickerTelegram,

4244

unpinMessageTelegram,

43-

} = await importTelegramSendModule();

45+

} = telegramSendModule;

44464547

const 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+166188

describe("sent-message-cache", () => {

167189

afterEach(() => {

168190

vi.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+19992164

it("retries media sends without message_thread_id when thread is missing", async () => {

2165+

const logFile = captureInfoLogs();

20002166

const chatId = "-100123";

20012167

const threadErr = new Error("400: Bad Request: message thread not found");

20022168

const sendPhoto = vi

@@ -2044,6 +2210,10 @@ describe("sendMessageTelegram", () => {

20442210

},

20452211

);

20462212

expect(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

});

2048221820492219

it("defaults outbound media uploads to 100MB", async () => {