慣性聚合 高效追讀感興趣之博客、新聞、科技資訊
閱原文 以慣性聚合開啟

推薦訂閱源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
量子位
M
Microsoft Research Blog - Microsoft Research
Microsoft Azure Blog
Microsoft Azure Blog
Jina AI
Jina AI
罗磊的独立博客
V
Visual Studio Blog
Last Week in AI
Last Week in AI
阮一峰的网络日志
阮一峰的网络日志
IT之家
IT之家
aimingoo的专栏
aimingoo的专栏
雷峰网
雷峰网
酷 壳 – CoolShell
酷 壳 – CoolShell
美团技术团队
博客园 - 三生石上(FineUI控件)
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
MongoDB | Blog
MongoDB | Blog
小众软件
小众软件
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog

Recent Commits to openclaw:main

fix(release): accept sha-verified publish evidence · openclaw/openclaw@7439d78 fix(ui): handle empty strings with minLength constraint in config sav… · openclaw/openclaw@3b3b2cc fix: treat aborted subagent lifecycle events as killed docs: add changelog for aborted subagent fix fix(agents): treat aborted subagent runs as terminal fix: prefer aborted stop reason over blocked lifecycle docs: update changelog for whatsapp reply fence fix(browser): validate inputs and redact remote URLs · openclaw/openclaw@bee15d4 fix(gateway): scope imported history identity · openclaw/openclaw@6d6b247 fix(cli): keep secrets configure JSON singular · openclaw/openclaw@97c63e6 fix(acp): require allow option for auto approvals · openclaw/openclaw@25ccadd fix(tools): tolerate out-of-scope autoreview findings · openclaw/openclaw@8cc9329 fix(plugins): fail stalled runtime operations · openclaw/openclaw@eeb5f12 fix: address PR review comments · openclaw/openclaw@08159d8 fix(node): avoid stale TLS pins when retargeting · openclaw/openclaw@679b677 fix(ci): address review sweep regressions fix(cli): keep completion and Twitch races bounded · openclaw/openclaw@6ce9e0d fix(cli): preserve command option state · openclaw/openclaw@15ff89b fix(cli): bound node media file writes · openclaw/openclaw@a4e95cf fix(twitch): wait through auth retry disconnects · openclaw/openclaw@9177860 fix(twitch): cancel pending clients during shutdown · openclaw/openclaw@e9bf111 docs(changelog): note CLI and plugin bug fixes · openclaw/openclaw@181d55e fix(plugins): avoid Signal and Twitch setup regressions · openclaw/openclaw@5b2703e fix(cli): preserve explicit command intent · openclaw/openclaw@9410eb3 fix(twitch): cancel auth retry disconnects · openclaw/openclaw@841cb12 fix(cli): keep plugin command metadata intact · openclaw/openclaw@9ab0af2 fix(plugins): stabilize Twitch and Signal setup fix: avoid duplicate media source reply transcripts · openclaw/openclaw@a10e152 fix: back source reply media in transcripts · openclaw/openclaw@39226ea fix: ignore replayed empty TUI finals · openclaw/openclaw@17fc1d1 fix: guard transcript source reply rewrites · openclaw/openclaw@b074dc5 fix: render late source reply finals in TUI · openclaw/openclaw@59b8aea test: narrow transcript rewrite message content access · openclaw/openclaw@81dee15 fix: preserve reply payload metadata · openclaw/openclaw@bfcd801 docs: add TUI source reply changelog · openclaw/openclaw@589fd92 fix: preserve reply metadata through media normalization · openclaw/openclaw@a238f03 fix: avoid double terminal chat events for source replies · openclaw/openclaw@6a0e030 test: cover source reply media transcript backing · openclaw/openclaw@321d98b fix: keep long Codex source replies alive · openclaw/openclaw@c93dda9 fix: broadcast source reply finals for chat runs · openclaw/openclaw@84ac31b fix: keep TUI watchdog runs active · openclaw/openclaw@84d278a fix: preserve source reply metadata through TTS fix: bound Codex post-reasoning source reply waits · openclaw/openclaw@f5b415f test: cover control ui source reply final retention · openclaw/openclaw@5534cad fix: keep source reply finals live in control ui · openclaw/openclaw@5e28574 fix: gracefully escalate process supervisor cancellations (#85865) · openclaw/openclaw@b13166b fix: preserve internal handoff status attribution [AI-assisted] (#85726) · openclaw/openclaw@f55e986 fix(browser): thread snapshot timeoutMs through agent tool and helper… · openclaw/openclaw@069c7b8 Disable Chrome MCP telemetry watchdog by default (#85886) · openclaw/openclaw@d581415 perf: cache stable gateway metadata · openclaw/openclaw@12f8227
修前景应答栅栏显隐 · openclaw/openclaw@bd91107
cavit99 · 2026-05-24 · via Recent Commits to openclaw:main
原本之文行序数异文行序数异文行变改

@@ -466,6 +466,30 @@ describe("deliverWebReply", () => {

466466

expect(logVerbose).toHaveBeenCalled();

467467

});

468468
469+

it("marks errors visible after accepted media delivery", async () => {

470+

const msg = makeMsg();

471+

const error = new Error("tail send failed");

472+

mockLoadedImageMedia();

473+

vi.mocked(msg.reply).mockRejectedValue(error);

474+
475+

await expect(

476+

deliverWebReply({

477+

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

478+

msg,

479+

maxMediaBytes: 1024 * 1024,

480+

textLimit: 7,

481+

replyLogger,

482+

skipLog: true,

483+

}),

484+

).rejects.toMatchObject({

485+

sentBeforeError: true,

486+

visibleReplySent: true,

487+

});

488+
489+

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

490+

expect(msg.reply).toHaveBeenCalled();

491+

});

492+
469493

it("preserves leading indentation after trimming only leading blank lines", async () => {

470494

const msg = makeMsg();

471495
原本之文行序数异文行序数异文行变改

@@ -83,6 +83,20 @@ function createWhatsAppReplyDeliveryReceipt(

8383

});

8484

}

8585
86+

function markWhatsAppVisibleDeliveryError(error: unknown): unknown {

87+

if (typeof error === "object" && error !== null && !Array.isArray(error)) {

88+

try {

89+

Object.assign(error, { sentBeforeError: true, visibleReplySent: true });

90+

return error;

91+

} catch {

92+

// Fall back to a wrapper when a platform error object is non-extensible.

93+

}

94+

}

95+

const visibleError = new Error("visible WhatsApp reply delivery failed", { cause: error });

96+

Object.assign(visibleError, { sentBeforeError: true, visibleReplySent: true });

97+

return visibleError;

98+

}

99+
86100

export async function deliverWebReply(params: {

87101

replyResult: ReplyPayload;

88102

normalizedReplyResult?: DeliverableWhatsAppOutboundPayload<ReplyPayload>;

@@ -150,15 +164,22 @@ export async function deliverWebReply(params: {

150164

};

151165
152166

const sendWithRetry = async <T>(fn: () => Promise<T>, label: string, maxAttempts = 3) => {

153-

return await sendWhatsAppOutboundWithRetry({

154-

send: fn,

155-

maxAttempts,

156-

onRetry: ({ attempt, maxAttempts: retryMaxAttempts, backoffMs, errorText }) => {

157-

logVerbose(

158-

`Retrying ${label} to ${msg.from} after failure (${attempt}/${retryMaxAttempts - 1}) in ${backoffMs}ms: ${errorText}`,

159-

);

160-

},

161-

});

167+

try {

168+

return await sendWhatsAppOutboundWithRetry({

169+

send: fn,

170+

maxAttempts,

171+

onRetry: ({ attempt, maxAttempts: retryMaxAttempts, backoffMs, errorText }) => {

172+

logVerbose(

173+

`Retrying ${label} to ${msg.from} after failure (${attempt}/${retryMaxAttempts - 1}) in ${backoffMs}ms: ${errorText}`,

174+

);

175+

},

176+

});

177+

} catch (error: unknown) {

178+

if (sendResults.some((result) => result.providerAccepted)) {

179+

throw markWhatsAppVisibleDeliveryError(error);

180+

}

181+

throw error;

182+

}

162183

};

163184
164185

// Text-only replies