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

推荐订阅源

人人都是产品经理
人人都是产品经理
博客园_首页
IT之家
IT之家
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Vercel News
Vercel News
美团技术团队
D
Docker
WordPress大学
WordPress大学
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
The Cloudflare Blog
Y
Y Combinator Blog
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
G
Google Developers Blog
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
月光博客
月光博客
MongoDB | Blog
MongoDB | Blog
S
SegmentFault 最新的问题
GbyAI
GbyAI
Hugging Face - Blog
Hugging Face - Blog
Microsoft Azure Blog
Microsoft Azure Blog
A
About on SuperTechFans

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
fix(whatsapp): track provider-accepted auto-replies · ope...
steipete · 2026-04-30 · via Recent Commits to openclaw:main

@@ -48,6 +48,26 @@ vi.mock("../media.js", () => ({

4848

let deliverWebReply: typeof import("./deliver-reply.js").deliverWebReply;

4949

let whatsappOutbound: typeof import("../outbound-adapter.js").whatsappOutbound;

505051+

function acceptedSendResult(kind: "media" | "text", id: string) {

52+

return {

53+

kind,

54+

messageId: id,

55+

messageIds: [id],

56+

keys: [{ id }],

57+

providerAccepted: true,

58+

};

59+

}

60+61+

function unacceptedSendResult(kind: "media" | "text") {

62+

return {

63+

kind,

64+

messageId: "unknown",

65+

messageIds: [],

66+

keys: [],

67+

providerAccepted: false,

68+

};

69+

}

70+5171

function makeMsg(): WebInboundMsg {

5272

return {

5373

from: "+10000000000",

@@ -58,8 +78,8 @@ function makeMsg(): WebInboundMsg {

5878

id: "msg-1",

5979

body: "latest batch body",

6080

senderJid: "222@s.whatsapp.net",

61-

reply: vi.fn(async () => undefined),

62-

sendMedia: vi.fn(async () => undefined),

81+

reply: vi.fn(async () => acceptedSendResult("text", "reply-sent-1")),

82+

sendMedia: vi.fn(async () => acceptedSendResult("media", "media-sent-1")),

6383

} as unknown as WebInboundMsg;

6484

}

6585

@@ -99,7 +119,7 @@ function expectFirstSendMediaPayload(msg: WebInboundMsg) {

99119100120

function mockSecondReplySuccess(msg: WebInboundMsg) {

101121

(msg.reply as unknown as { mockResolvedValueOnce: (v: unknown) => void }).mockResolvedValueOnce(

102-

undefined,

122+

acceptedSendResult("text", "reply-retry-2"),

103123

);

104124

}

105125

@@ -162,7 +182,7 @@ describe("deliverWebReply", () => {

162182

it("sends chunked text replies and logs a summary", async () => {

163183

const msg = makeMsg();

164184165-

await deliverWebReply({

185+

const delivery = await deliverWebReply({

166186

replyResult: { text: "aaaaaa" },

167187

msg,

168188

maxMediaBytes: 1024 * 1024,

@@ -175,6 +195,32 @@ describe("deliverWebReply", () => {

175195

expect(msg.reply).toHaveBeenNthCalledWith(1, "aaa", undefined);

176196

expect(msg.reply).toHaveBeenNthCalledWith(2, "aaa", undefined);

177197

expect(replyLogger.info).toHaveBeenCalledWith(expect.any(Object), "auto-reply sent (text)");

198+

expect(delivery.providerAccepted).toBe(true);

199+

expect(delivery.messageIds).toEqual(["reply-sent-1"]);

200+

});

201+202+

it("reports text replies that Baileys did not accept", async () => {

203+

const msg = makeMsg();

204+

vi.mocked(msg.reply).mockResolvedValueOnce(unacceptedSendResult("text"));

205+206+

const delivery = await deliverWebReply({

207+

replyResult: { text: "hello" },

208+

msg,

209+

maxMediaBytes: 1024 * 1024,

210+

textLimit: 200,

211+

replyLogger,

212+

skipLog: true,

213+

});

214+215+

expect(msg.reply).toHaveBeenCalledTimes(1);

216+

expect(delivery).toMatchObject({

217+

messageIds: [],

218+

providerAccepted: false,

219+

});

220+

expect(replyLogger.warn).toHaveBeenCalledWith(

221+

expect.any(Object),

222+

"auto-reply text was not accepted by WhatsApp provider",

223+

);

178224

});

179225180226

it("strips raw XML tool-call blocks before WhatsApp text delivery", async () => {

@@ -421,7 +467,7 @@ describe("deliverWebReply", () => {

421467

mockFirstSendMediaFailure(msg, "socket reset");

422468

(

423469

msg.sendMedia as unknown as { mockResolvedValueOnce: (v: unknown) => void }

424-

).mockResolvedValueOnce(undefined);

470+

).mockResolvedValueOnce(acceptedSendResult("media", "media-retry-2"));

425471426472

await deliverWebReply({

427473

replyResult: { text: "caption", mediaUrl: "http://example.com/img.jpg" },

@@ -484,7 +530,7 @@ describe("deliverWebReply", () => {

484530

mockFirstSendMediaFailure(msg, "boom");

485531

(

486532

msg.sendMedia as unknown as { mockResolvedValueOnce: (v: unknown) => void }

487-

).mockResolvedValueOnce(undefined);

533+

).mockResolvedValueOnce(acceptedSendResult("media", "media-second-1"));

488534489535

await deliverWebReply({

490536

replyResult: {