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

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Security Latest
Security Latest
Jina AI
Jina AI
爱范儿
爱范儿
Attack and Defense Labs
Attack and Defense Labs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
GbyAI
GbyAI
N
News | PayPal Newsroom
Last Week in AI
Last Week in AI
V
Visual Studio Blog
SecWiki News
SecWiki News
H
Heimdal Security Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
腾讯CDC
L
LINUX DO - 热门话题
I
InfoQ
罗磊的独立博客
博客园_首页
Know Your Adversary
Know Your Adversary
T
The Exploit Database - CXSecurity.com
博客园 - 【当耐特】
阮一峰的网络日志
阮一峰的网络日志
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Threat Research - Cisco Blogs
美团技术团队
IT之家
IT之家
AWS News Blog
AWS News Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
Netflix TechBlog - Medium
Help Net Security
Help Net Security
S
Secure Thoughts
Microsoft Security Blog
Microsoft Security Blog
Schneier on Security
Schneier on Security
Spread Privacy
Spread Privacy
B
Blog RSS Feed
N
News and Events Feed by Topic
L
Lohrmann on Cybersecurity
Google Online Security Blog
Google Online Security Blog
Microsoft Azure Blog
Microsoft Azure Blog
N
News and Events Feed by Topic
I
Intezer
Blog — PlanetScale
Blog — PlanetScale
云风的 BLOG
云风的 BLOG
A
Arctic Wolf
C
Cyber Attacks, Cyber Crime and Cyber Security
G
Google Developers Blog
The Register - Security
The Register - Security
The GitHub Blog
The GitHub Blog
MyScale Blog
MyScale Blog
F
Full Disclosure

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 test: trim doctor command hotspots · openclaw/openclaw@c66f16a test: isolate agent auth and spawn hotspots · openclaw/openclaw@9285935 test: stabilize MCP startup disposal race · openclaw/openclaw@dd9d2eb test: merge browser contract server suites · openclaw/openclaw@5817a76 test: narrow ollama provider discovery setup · openclaw/openclaw@a0d9598 build: declare qa-lab aimock runtime dependency · openclaw/openclaw@24431e5 test: speed up safe-bins exec harness · openclaw/openclaw@ee856ab test: preserve tool helpers in embedded runner mocks · openclaw/openclaw@acd86a0 refactor: move memory embeddings into provider plugins · openclaw/openclaw@77e6e4c test: reuse system-run temp fixtures · openclaw/openclaw@7e9ff0f test: trim hotspot wait overhead · openclaw/openclaw@12a59b0 Check: avoid duplicate boundary prep · openclaw/openclaw@baf11b8 test: reduce hotspot fixture overhead · openclaw/openclaw@3a59edd feat(ui): overhaul settings and slash command UX (#67819) thanks @Bun… · openclaw/openclaw@2cfb660 QA Matrix: exit cleanly on failure · openclaw/openclaw@42805d2 QA Matrix: isolate scenario coverage · openclaw/openclaw@7e659e1 Matrix: refresh crypto bootstrap state · openclaw/openclaw@94081d8 QA Lab: add provider registry · openclaw/openclaw@bb7e982 Matrix: add plugin changelog · openclaw/openclaw@4acab55 test: trim more hotspot overhead · openclaw/openclaw@f485311 test: trim remaining hotspot tests · openclaw/openclaw@6ba8626 test: narrow hotspot mocks · openclaw/openclaw@dbc8179 test: isolate gemini embedding request helpers · openclaw/openclaw@cd330f5 test: trim memory and mcp hotspots · openclaw/openclaw@fd48dfa test: slim provider registry mocks · openclaw/openclaw@2e08c77 test: harden Parallels update smoke · openclaw/openclaw@1a98090 feat: default Anthropic to Opus 4.7 · openclaw/openclaw@628b454 fix: harden node-host shell payload mutability checks · openclaw/openclaw@75c551e fix: land node-host approval binding for native binaries (#66731) (th… · openclaw/openclaw@29919bb CI: add daily schedule to CodeQL workflow (#67645) · openclaw/openclaw@69d25f5 fix(gateway): capture config hash after plugin auto-enable to prevent… · openclaw/openclaw@8c11210 fix: repair sanitized replay tool results before send (#67620) (thank… · openclaw/openclaw@c3c7a99 fix: restrict HTML timeout short-circuit to transient statuses · openclaw/openclaw@de129a6 fix: keep TUI watchdog bound to active run (#67401) (thanks @xantorres) · openclaw/openclaw@3525273 Gateway/skills: dedupe skills prefix-match + drop dead fallback on log · openclaw/openclaw@d7f489f Extensions/lmstudio: back off inference preload after consecutive fai… · openclaw/openclaw@b555214 TUI/streaming: add watchdog that resets the activity indicator after … · openclaw/openclaw@f44ab20 Agents/tool-loop: enable unknown-tool stream guard by default · openclaw/openclaw@36ed367 Gateway/skills: invalidate session skills snapshot on config write · openclaw/openclaw@b23d59a fix: classify HTML provider error pages correctly (#67642) (thanks @s… · openclaw/openclaw@e588e90 fix(skills): remove unused model-usage import (#67641) · openclaw/openclaw@55f05df docs(changelog): credit codex fix superseded PRs · openclaw/openclaw@e485f24 fix(openai-codex): normalize stale transport metadata in resolution a… · openclaw/openclaw@90801ba CI: pin Docker-related GitHub Actions (#67632) · openclaw/openclaw@f697b01 Android: modernize WebView and discovery API usage (#67627) · openclaw/openclaw@44a6e50 fix(deps): bump hono to 4.12.14 and @hono/node-server to 1.19.14 (GHS… · openclaw/openclaw@fbccc18 fix(deps): bump dompurify to 3.4.0 (#67614) · openclaw/openclaw@2c2dc00 CI: add explicit permissions to all workflow jobs (fixes code-scannin… · openclaw/openclaw@01b7516 fix: register bundled TTS providers and route overrides correctly (#6… · openclaw/openclaw@6ea3cdd fix: align host tilde paths with OS home (#62804) (thanks @stainlu) · openclaw/openclaw@ecfaf64 fix: flush creds queue before reconnect socket open (#67464) (thanks … · openclaw/openclaw@405c63f fix: strip standalone <function> tool call tags from visible text (#6… · openclaw/openclaw@78df859 fix(agents): preserve cli session metadata before transcript persist … · openclaw/openclaw@898fd04 docs(changelog): move cli transcript entry · openclaw/openclaw@c1817c6 fix(agents): normalize cli transcript api field · openclaw/openclaw@3a3fae0 docs(changelog): note cli transcript persistence · openclaw/openclaw@6c343f1 fix(agents): persist cli transcript turns · openclaw/openclaw@b8ef507 fix(msteams): harden security-sensitive flows (#65841) · openclaw/openclaw@c56b56e [Dashboard] Fix exec approval modal overflow for long command content… · openclaw/openclaw@053c5b0 Docs: remove QA changelog entry · openclaw/openclaw@7fd5771 QA: fix private runtime source loading (#67428) · openclaw/openclaw@d5933af docs(gateway): correct protocol.md schema path, hello-ok example, aut… · openclaw/openclaw@489404d CI: pin Node 22 runners to 22.18.0 · openclaw/openclaw@4ffa621 models.authStatus: normalize provider ids + tighten env-backed escape… · openclaw/openclaw@f2fdb9d Update CHANGELOG.md · openclaw/openclaw@7694a92 test(parallels): clean up npm update guard jobs · openclaw/openclaw@045ea7b Plugins: prefer scanDir override paths · openclaw/openclaw@b2974da fix(dreaming): default storage.mode to "separate" so phase blocks sto… · openclaw/openclaw@8c392f0 fix(memory-core): skip dreaming transcript ingestion via session stor… · openclaw/openclaw@a1b01f0 fix: dedupe replayed exec.finished node events (#67281) · openclaw/openclaw@5dcf526
fix(discord): fail dropped final reply delivery · openclaw/openclaw@9e97cdb
Patrick-Eric · 2026-05-05 · via Recent Commits to openclaw:main
Original file line numberDiff line numberDiff line change

@@ -69,6 +69,7 @@ Docs: https://docs.openclaw.ai

6969

- Plugins/runtime-deps: include `json5` in the memory-core plugin runtime dependency set so packaged `memory_search` sandboxes can resolve generated OpenClaw runtime chunks that parse JSON5 config. Fixes #77461.

7070

- Codex harness: preserve app-server usage-limit reset details and deliver OpenClaw-owned runtime failure notices through tool-only source-reply mode, so Telegram and other chat channels tell users when Codex subscription limits or API failures block a turn instead of going silent. (#77557) Thanks @pashpashpash.

7171

- Agents/OpenAI: default direct OpenAI Responses models to the SSE transport instead of WebSocket auto-selection, preventing pi runtime chat turns from hanging on servers where the WebSocket path stalls while the OpenAI HTTP stream works. Thanks @vincentkoc.

72+

- Discord/replies: treat failed final reply delivery as a failed turn instead of counting it as a delivered automatic visible reply, so guild/channel turns no longer show done when the final message was dropped. Fixes #77520.

7273

- Discord: prefer IPv4 for Discord REST and gateway WebSocket startup paths so IPv4-only networks no longer stall before Gateway READY and inbound message dispatch. Fixes #77398; refs #77526. Thanks @Beandon13.

7374

- Channels/plugins: key bundled package-state probes, env/config presence, and read-only command defaults by channel id instead of manifest plugin id, preserving setup and native-command detection for channel plugins whose package id differs from the channel alias. Thanks @vincentkoc.

7475

- Docker: prune package-excluded plugin dist directories from runtime images unless the build explicitly opts that plugin in, so official external plugins such as Feishu stay install-on-demand instead of shipping partial metadata without compiled runtime output. Fixes #77424. Thanks @vincentkoc.

Original file line numberDiff line numberDiff line change

@@ -139,9 +139,11 @@ type DispatchInboundParams = {

139139

};

140140

const dispatchInboundMessage = vi.hoisted(() =>

141141

vi.fn<

142-

(

143-

params?: DispatchInboundParams,

144-

) => Promise<{ queuedFinal: boolean; counts: { final: number; tool: number; block: number } }>

142+

(params?: DispatchInboundParams) => Promise<{

143+

queuedFinal: boolean;

144+

counts: { final: number; tool: number; block: number };

145+

failedCounts?: { final?: number; tool?: number; block?: number };

146+

}>

145147

>(async (_params?: DispatchInboundParams) => ({

146148

queuedFinal: false,

147149

counts: { final: 0, tool: 0, block: 0 },

@@ -621,6 +623,22 @@ describe("processDiscordMessage ack reactions", () => {

621623

expect(emojis).not.toContain(DEFAULT_EMOJIS.coding);

622624

});

623625
626+

it("marks automatic visible replies as failed when final Discord delivery fails", async () => {

627+

dispatchInboundMessage.mockResolvedValueOnce({

628+

queuedFinal: false,

629+

counts: { final: 0, tool: 0, block: 0 },

630+

failedCounts: { final: 1 },

631+

});

632+
633+

const ctx = await createAutomaticSourceDeliveryContext();

634+
635+

await runProcessDiscordMessage(ctx);

636+
637+

const emojis = getReactionEmojis();

638+

expect(emojis).toContain(DEFAULT_EMOJIS.error);

639+

expect(emojis).not.toContain(DEFAULT_EMOJIS.done);

640+

});

641+
624642

it("can bind status reactions to an explicitly tracked reaction target", async () => {

625643

vi.useFakeTimers();

626644

dispatchInboundMessage.mockImplementationOnce(async (params?: DispatchInboundParams) => {

Original file line numberDiff line numberDiff line change

@@ -802,6 +802,7 @@ export async function processDiscordMessage(

802802

markDispatchIdle();

803803

}

804804

}

805+

const finalDeliveryFailed = (dispatchResult?.failedCounts?.final ?? 0) > 0;

805806

if (statusReactionsActive) {

806807

if (dispatchAborted) {

807808

if (removeAckAfterReply) {

@@ -810,14 +811,18 @@ export async function processDiscordMessage(

810811

void statusReactions.restoreInitial();

811812

}

812813

} else {

813-

if (dispatchError) {

814+

if (dispatchError || finalDeliveryFailed) {

814815

await statusReactions.setError();

815816

} else {

816817

await statusReactions.setDone();

817818

}

818819

if (removeAckAfterReply) {

819820

void (async () => {

820-

await sleep(dispatchError ? DEFAULT_TIMING.errorHoldMs : DEFAULT_TIMING.doneHoldMs);

821+

await sleep(

822+

dispatchError || finalDeliveryFailed

823+

? DEFAULT_TIMING.errorHoldMs

824+

: DEFAULT_TIMING.doneHoldMs,

825+

);

821826

await statusReactions.clear();

822827

})();

823828

} else {

Original file line numberDiff line numberDiff line change

@@ -3,7 +3,9 @@ import type { RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";

33

import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";

44

import type { RequestClient } from "../internal/discord.js";

55
6-

const deliverOutboundPayloadsMock = vi.hoisted(() => vi.fn(async () => []));

6+

const deliverOutboundPayloadsMock = vi.hoisted(() =>

7+

vi.fn(async () => [{ messageId: "msg-1", channelId: "channel-1" }]),

8+

);

79

const sendMessageDiscordMock = vi.hoisted(() => vi.fn());

810

const sendVoiceMessageDiscordMock = vi.hoisted(() => vi.fn());

911

@@ -57,7 +59,7 @@ describe("deliverDiscordReply", () => {

5759
5860

beforeEach(() => {

5961

deliverOutboundPayloadsMock.mockClear();

60-

deliverOutboundPayloadsMock.mockResolvedValue([]);

62+

deliverOutboundPayloadsMock.mockResolvedValue([{ messageId: "msg-1", channelId: "channel-1" }]);

6163

sendMessageDiscordMock.mockReset().mockResolvedValue({

6264

messageId: "msg-1",

6365

channelId: "channel-1",

@@ -105,6 +107,22 @@ describe("deliverDiscordReply", () => {

105107

);

106108

});

107109
110+

it("fails when shared outbound accepts a final reply but delivers no Discord message", async () => {

111+

deliverOutboundPayloadsMock.mockResolvedValueOnce([]);

112+
113+

await expect(

114+

deliverDiscordReply({

115+

replies: [{ text: "lost reply" }],

116+

target: "channel:101",

117+

token: "token",

118+

accountId: "default",

119+

runtime,

120+

cfg,

121+

textLimit: 2000,

122+

}),

123+

).rejects.toThrow("discord final reply produced no delivered message for channel:101");

124+

});

125+
108126

it("strips internal execution trace lines at the final Discord send boundary", async () => {

109127

await deliverDiscordReply({

110128

replies: [

Original file line numberDiff line numberDiff line change

@@ -181,7 +181,7 @@ export async function deliverDiscordReply(params: {

181181

return;

182182

}

183183
184-

await deliverOutboundPayloads({

184+

const results = await deliverOutboundPayloads({

185185

cfg: params.cfg,

186186

channel: "discord",

187187

to: delivery.to,

@@ -205,4 +205,7 @@ export async function deliverDiscordReply(params: {

205205

requesterAccountId: params.accountId,

206206

}),

207207

});

208+

if (results.length === 0) {

209+

throw new Error(`discord final reply produced no delivered message for ${delivery.to}`);

210+

}

208211

}

Original file line numberDiff line numberDiff line change

@@ -283,6 +283,36 @@ describe("withReplyDispatcher", () => {

283283

});

284284

});

285285
286+

it("reconciles queuedFinal and counts after dispatcher-side delivery failure", async () => {

287+

const dispatcher = {

288+

sendToolResult: () => true,

289+

sendBlockReply: () => true,

290+

sendFinalReply: () => true,

291+

getQueuedCounts: () => ({ tool: 0, block: 0, final: 0 }),

292+

getCancelledCounts: () => ({ tool: 0, block: 0, final: 0 }),

293+

getFailedCounts: () => ({ tool: 0, block: 0, final: 1 }),

294+

markComplete: () => undefined,

295+

waitForIdle: async () => undefined,

296+

} satisfies ReplyDispatcher;

297+

hoisted.dispatchReplyFromConfigMock.mockResolvedValueOnce({

298+

queuedFinal: true,

299+

counts: { tool: 0, block: 0, final: 1 },

300+

});

301+
302+

const result = await dispatchInboundMessage({

303+

ctx: buildTestCtx(),

304+

cfg: {} as OpenClawConfig,

305+

dispatcher,

306+

replyResolver: async () => ({ text: "ok" }),

307+

});

308+
309+

expect(result).toEqual({

310+

queuedFinal: false,

311+

counts: { tool: 0, block: 0, final: 0 },

312+

failedCounts: { tool: 0, block: 0, final: 1 },

313+

});

314+

});

315+
286316

it("uses CommandTargetSessionKey for silent-reply policy on native command turns", async () => {

287317

hoisted.createReplyDispatcherWithTypingMock.mockReturnValueOnce({

288318

dispatcher: createDispatcher([]),

Original file line numberDiff line numberDiff line change

@@ -103,19 +103,36 @@ function finalizeDispatchResult(

103103

dispatcher: ReplyDispatcher,

104104

): DispatchFromConfigResult {

105105

const cancelledCounts = dispatcher.getCancelledCounts?.();

106-

if (!cancelledCounts) {

106+

const failedCounts = dispatcher.getFailedCounts?.();

107+

if (!cancelledCounts && !failedCounts) {

107108

return result;

108109

}

109110
111+

const resultCounts = {

112+

tool: result.counts?.tool ?? 0,

113+

block: result.counts?.block ?? 0,

114+

final: result.counts?.final ?? 0,

115+

};

110116

const counts = {

111-

tool: Math.max(0, result.counts.tool - cancelledCounts.tool),

112-

block: Math.max(0, result.counts.block - cancelledCounts.block),

113-

final: Math.max(0, result.counts.final - cancelledCounts.final),

117+

tool: Math.max(0, resultCounts.tool - (cancelledCounts?.tool ?? 0) - (failedCounts?.tool ?? 0)),

118+

block: Math.max(

119+

0,

120+

resultCounts.block - (cancelledCounts?.block ?? 0) - (failedCounts?.block ?? 0),

121+

),

122+

final: Math.max(

123+

0,

124+

resultCounts.final - (cancelledCounts?.final ?? 0) - (failedCounts?.final ?? 0),

125+

),

114126

};

127+

const hasFailedCounts =

128+

(failedCounts?.tool ?? 0) > 0 ||

129+

(failedCounts?.block ?? 0) > 0 ||

130+

(failedCounts?.final ?? 0) > 0;

115131

return {

116132

...result,

117133

queuedFinal: result.queuedFinal && counts.final > 0,

118134

counts,

135+

...(hasFailedCounts ? { failedCounts } : {}),

119136

};

120137

}

121138
Original file line numberDiff line numberDiff line change

@@ -8,6 +8,7 @@ import type { ReplyDispatchKind, ReplyDispatcher } from "./reply-dispatcher.type

88

export type DispatchFromConfigResult = {

99

queuedFinal: boolean;

1010

counts: Record<ReplyDispatchKind, number>;

11+

failedCounts?: Partial<Record<ReplyDispatchKind, number>>;

1112

sourceReplyDeliveryMode?: SourceReplyDeliveryMode;

1213

};

1314