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

推荐订阅源

有赞技术团队
有赞技术团队
美团技术团队
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
阮一峰的网络日志
阮一峰的网络日志
S
SegmentFault 最新的问题
博客园_首页
雷峰网
雷峰网
V
V2EX
The Cloudflare Blog
博客园 - 三生石上(FineUI控件)
量子位
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 聂微东
V
Visual Studio Blog
Hugging Face - Blog
Hugging Face - Blog
博客园 - 【当耐特】
Jina AI
Jina AI
月光博客
月光博客
L
LangChain Blog

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(agents): bound compaction wake retry timeouts · openc...
steipete · 2026-05-28 · via Recent Commits to openclaw:main

@@ -222,42 +222,39 @@ function resolveCompactionSteerRetryDelaysMs() {

222222

: ([1_000, 2_000, 4_000, 8_000] as const);

223223

}

224224225-

// Wake an active requester run, retrying through two transient outcomes:

226-

// - transcript_commit_wait_unsupported: retry once without the transcript-commit

227-

// wait (best-effort steering for runtimes that cannot wait for commit).

228-

// - compacting: the run becomes steerable again once compaction finishes, so

229-

// wait through compaction and retry the same wake, bounded by cancellation and

230-

// a finite backoff schedule (well within the delivery timeout).

231-

// Both the steer path and the generated-completion active wake use this helper so

232-

// the retry behavior stays consistent. Other failure reasons are returned as-is

233-

// for the caller's existing fallback handling. The two transient retries are

234-

// handled in a single loop so a run that compacts and then reports

235-

// transcript_commit_wait_unsupported still gets the best-effort retry.

225+

// Wake an active requester run through transient compacting and transcript-wait

226+

// outcomes. Both active-wake call sites use one loop so delivery deadlines and

227+

// best-effort transcript retry stay consistent.

236228

async function resolveActiveWakeWithRetries(

237229

sessionId: string,

238230

message: string,

239231

wakeOptions: EmbeddedAgentQueueMessageOptions,

240232

signal?: AbortSignal,

241233

): Promise<EmbeddedAgentQueueMessageOutcome> {

242-

let currentOptions = wakeOptions;

243-

let outcome = await resolveQueueEmbeddedAgentMessageOutcome(

244-

sessionId,

245-

message,

246-

currentOptions,

247-

);

248-

const compactionRetryDelaysMs = resolveCompactionSteerRetryDelaysMs();

249-

let compactionRetryIndex = 0;

250-

// Bound compaction waiting by the delivery timeout (the window the issue asks

251-

// us to wait within), not just the fixed backoff schedule: a compaction that

252-

// finishes after the schedule is exhausted but still inside the delivery

253-

// timeout should keep being retried. The backoff schedule controls the gap

254-

// between attempts; once it is exhausted the last delay is reused until the

255-

// deadline. A missing/zero timeout falls back to the bounded schedule only.

234+

// Bound the whole active wake by the caller's delivery window. Each retry

235+

// passes only the remaining window into transcript-commit waiting so a

236+

// near-deadline retry cannot add another full timeout.

256237

const compactionDeadlineMs =

257-

typeof wakeOptions.deliveryTimeoutMs === "number" &&

258-

wakeOptions.deliveryTimeoutMs > 0

238+

typeof wakeOptions.deliveryTimeoutMs === "number" && wakeOptions.deliveryTimeoutMs > 0

259239

? Date.now() + wakeOptions.deliveryTimeoutMs

260240

: undefined;

241+

let currentOptions = wakeOptions;

242+

const resolveRetryOptions = (): EmbeddedAgentQueueMessageOptions | undefined => {

243+

if (compactionDeadlineMs === undefined) {

244+

return currentOptions;

245+

}

246+

const remainingDeliveryTimeoutMs = compactionDeadlineMs - Date.now();

247+

if (remainingDeliveryTimeoutMs <= 0) {

248+

return undefined;

249+

}

250+

return {

251+

...currentOptions,

252+

deliveryTimeoutMs: remainingDeliveryTimeoutMs,

253+

};

254+

};

255+

let outcome = await resolveQueueEmbeddedAgentMessageOutcome(sessionId, message, currentOptions);

256+

const compactionRetryDelaysMs = resolveCompactionSteerRetryDelaysMs();

257+

let compactionRetryIndex = 0;

261258

for (;;) {

262259

if (outcome.queued || signal?.aborted) {

263260

break;

@@ -269,19 +266,17 @@ async function resolveActiveWakeWithRetries(

269266

const bestEffortOptions = { ...currentOptions };

270267

delete bestEffortOptions.waitForTranscriptCommit;

271268

currentOptions = bestEffortOptions;

272-

outcome = await resolveQueueEmbeddedAgentMessageOutcome(

273-

sessionId,

274-

message,

275-

currentOptions,

276-

);

269+

outcome = await resolveQueueEmbeddedAgentMessageOutcome(sessionId, message, currentOptions);

277270

continue;

278271

}

279272

if (outcome.reason === "compacting") {

280-

const withinDeadline =

281-

compactionDeadlineMs === undefined

273+

const remainingDeliveryTimeoutMs =

274+

compactionDeadlineMs === undefined ? undefined : compactionDeadlineMs - Date.now();

275+

const canRetry =

276+

remainingDeliveryTimeoutMs === undefined

282277

? compactionRetryIndex < compactionRetryDelaysMs.length

283-

: Date.now() < compactionDeadlineMs;

284-

if (!withinDeadline) {

278+

: remainingDeliveryTimeoutMs > 0;

279+

if (!canRetry) {

285280

break;

286281

}

287282

// Use the next scheduled backoff delay; once the schedule is exhausted,

@@ -294,22 +289,22 @@ async function resolveActiveWakeWithRetries(

294289

// not sleep past the deadline (which would overrun the delivery timeout).

295290

// If no time remains, stop retrying and let the fallback handle it.

296291

const delayMs =

297-

compactionDeadlineMs === undefined

292+

remainingDeliveryTimeoutMs === undefined

298293

? scheduledDelayMs

299-

: Math.min(scheduledDelayMs, compactionDeadlineMs - Date.now());

300-

if (delayMs <= 0 && compactionDeadlineMs !== undefined) {

294+

: Math.min(scheduledDelayMs, remainingDeliveryTimeoutMs);

295+

if (delayMs <= 0 && remainingDeliveryTimeoutMs !== undefined) {

301296

break;

302297

}

303298

await waitForAnnounceRetryDelay(delayMs, signal);

304299

if (signal?.aborted) {

305300

break;

306301

}

307302

compactionRetryIndex += 1;

308-

outcome = await resolveQueueEmbeddedAgentMessageOutcome(

309-

sessionId,

310-

message,

311-

currentOptions,

312-

);

303+

const retryOptions = resolveRetryOptions();

304+

if (!retryOptions) {

305+

break;

306+

}

307+

outcome = await resolveQueueEmbeddedAgentMessageOutcome(sessionId, message, retryOptions);

313308

continue;

314309

}

315310

break;