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

推荐订阅源

雷峰网
雷峰网
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Hugging Face - Blog
Hugging Face - Blog
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - Franky
MyScale Blog
MyScale Blog
A
About on SuperTechFans
博客园_首页
B
Blog RSS Feed
Martin Fowler
Martin Fowler
大猫的无限游戏
大猫的无限游戏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Vercel News
Vercel News
C
Check Point Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园 - 【当耐特】
M
MIT News - Artificial intelligence
宝玉的分享
宝玉的分享
T
Tailwind CSS Blog
I
InfoQ
罗磊的独立博客

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(channels): bound capabilities probes · openclaw/openc...
vincentkoc · 2026-06-22 · via Recent Commits to openclaw:main

@@ -53,6 +53,93 @@ type ChannelCapabilitiesReport = {

5353

diagnostics?: ChannelCapabilitiesDiagnostics;

5454

};

555556+

const CHANNEL_CAPABILITIES_TIMEOUT_MAX_MS = 30_000;

57+58+

type ChannelCapabilitiesStepResult<T> =

59+

| { kind: "value"; value: T }

60+

| { kind: "error"; error: unknown }

61+

| { kind: "timeout" };

62+63+

function resolveChannelCapabilitiesTimeoutMs(timeoutMs: number) {

64+

return Math.min(timeoutMs, CHANNEL_CAPABILITIES_TIMEOUT_MAX_MS);

65+

}

66+67+

async function raceChannelCapabilitiesStep<T>(params: {

68+

timeoutMs: number;

69+

run: () => Promise<T> | T;

70+

}): Promise<ChannelCapabilitiesStepResult<T>> {

71+

let timeout: ReturnType<typeof setTimeout> | undefined;

72+

const timeoutPromise = new Promise<ChannelCapabilitiesStepResult<T>>((resolve) => {

73+

timeout = setTimeout(() => resolve({ kind: "timeout" }), params.timeoutMs);

74+

timeout.unref?.();

75+

});

76+

const resultPromise: Promise<ChannelCapabilitiesStepResult<T>> = Promise.resolve()

77+

.then(params.run)

78+

.then(

79+

(value): ChannelCapabilitiesStepResult<T> => ({ kind: "value", value }),

80+

(error: unknown): ChannelCapabilitiesStepResult<T> => ({ kind: "error", error }),

81+

);

82+

const result = await Promise.race([resultPromise, timeoutPromise]);

83+

if (timeout) {

84+

clearTimeout(timeout);

85+

}

86+

return result;

87+

}

88+89+

async function runChannelCapabilitiesProbe(params: {

90+

timeoutMs: number;

91+

run: () => unknown;

92+

}): Promise<unknown> {

93+

const result = await raceChannelCapabilitiesStep(params);

94+

switch (result.kind) {

95+

case "value":

96+

return result.value;

97+

case "timeout":

98+

return {

99+

ok: false,

100+

timedOut: true,

101+

error: `probe timed out after ${params.timeoutMs}ms`,

102+

};

103+

case "error":

104+

return { ok: false, error: formatErrorMessage(result.error) };

105+

}

106+

return undefined;

107+

}

108+109+

async function runChannelCapabilitiesDiagnostics(params: {

110+

timeoutMs: number;

111+

run: () =>

112+

| Promise<ChannelCapabilitiesDiagnostics | undefined>

113+

| ChannelCapabilitiesDiagnostics

114+

| undefined;

115+

}): Promise<ChannelCapabilitiesDiagnostics | undefined> {

116+

const result = await raceChannelCapabilitiesStep(params);

117+

switch (result.kind) {

118+

case "value":

119+

return result.value;

120+

case "timeout":

121+

return {

122+

lines: [

123+

{

124+

text: `Diagnostics: timed out after ${params.timeoutMs}ms`,

125+

tone: "error",

126+

},

127+

],

128+

details: { timedOut: true },

129+

};

130+

case "error":

131+

return {

132+

lines: [

133+

{

134+

text: `Diagnostics: failed (${formatErrorMessage(result.error)})`,

135+

tone: "error",

136+

},

137+

],

138+

};

139+

}

140+

return undefined;

141+

}

142+56143

function formatSupport(capabilities?: ChannelCapabilities) {

57144

if (!capabilities) {

58145

return "unknown";

@@ -157,25 +244,29 @@ async function resolveChannelReports(params: {

157244

: (resolvedAccount as { enabled?: boolean }).enabled !== false;

158245

let probe: unknown;

159246

if (configured && enabled && plugin.status?.probeAccount) {

160-

try {

161-

probe = await plugin.status.probeAccount({

162-

account: resolvedAccount,

163-

timeoutMs,

164-

cfg,

165-

});

166-

} catch (err) {

167-

probe = { ok: false, error: formatErrorMessage(err) };

168-

}

247+

probe = await runChannelCapabilitiesProbe({

248+

timeoutMs,

249+

run: () =>

250+

plugin.status?.probeAccount?.({

251+

account: resolvedAccount,

252+

timeoutMs,

253+

cfg,

254+

}),

255+

});

169256

}

170257171258

const diagnostics =

172-

configured && enabled

173-

? await plugin.status?.buildCapabilitiesDiagnostics?.({

174-

account: resolvedAccount,

259+

configured && enabled && plugin.status?.buildCapabilitiesDiagnostics

260+

? await runChannelCapabilitiesDiagnostics({

175261

timeoutMs,

176-

cfg,

177-

probe,

178-

target: params.target,

262+

run: () =>

263+

plugin.status?.buildCapabilitiesDiagnostics?.({

264+

account: resolvedAccount,

265+

timeoutMs,

266+

cfg,

267+

probe,

268+

target: params.target,

269+

}),

179270

})

180271

: undefined;

181272

const discoveredActions = resolveMessageActionDiscoveryForPlugin({

@@ -221,7 +312,9 @@ export async function channelsCapabilitiesCommand(

221312

return;

222313

}

223314

let cfg = loadedCfg;

224-

const timeoutMs = parseTimeoutMsWithFallback(opts.timeout, 10_000);

315+

const timeoutMs = resolveChannelCapabilitiesTimeoutMs(

316+

parseTimeoutMsWithFallback(opts.timeout, 10_000),

317+

);

225318

const rawChannel = normalizeLowercaseStringOrEmpty(opts.channel);

226319

const rawTarget = normalizeOptionalString(opts.target) ?? "";

227320

@@ -350,10 +443,12 @@ export async function channelsCapabilitiesCommand(

350443

const enabledLabel = report.enabled === false ? "disabled" : "enabled";

351444

lines.push(`Status: ${configuredLabel}, ${enabledLabel}`);

352445

}

353-

const probeLines =

354-

report.plugin.status?.formatCapabilitiesProbe?.({

355-

probe: report.probe,

356-

}) ?? formatGenericProbeLines(report.probe);

446+

const formattedProbeLines = report.plugin.status?.formatCapabilitiesProbe?.({

447+

probe: report.probe,

448+

});

449+

const probeLines = formattedProbeLines?.length

450+

? formattedProbeLines

451+

: formatGenericProbeLines(report.probe);

357452

if (probeLines.length > 0) {

358453

lines.push(...probeLines.map(renderDisplayLine));

359454

} else if (report.configured && report.enabled) {