From dcb921944a073a1ebdce462743644449eeb48d23 Mon Sep 17 00:00:00 2001 From: taw0002 <42811278+taw0002@users.noreply.github.com> Date: Thu, 12 Feb 2026 08:55:32 -0500 Subject: [PATCH] fix: prevent double compaction caused by cache-ttl entry bypassing guard (#13514) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move appendCacheTtlTimestamp() to after prompt + compaction retry completes instead of before. The previous placement inserted a custom entry (openclaw.cache-ttl) between compaction and the next prompt, which broke pi-coding-agent's prepareCompaction() guard — the guard only checks if the last entry is type 'compaction', and the cache-ttl custom entry made it type 'custom', allowing an immediate second compaction at very low token counts (e.g. 5,545 tokens) that nuked all preserved context. Fixes #9282 Relates to #12170 --- src/agents/pi-embedded-runner/run/attempt.ts | 27 ++++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/agents/pi-embedded-runner/run/attempt.ts b/src/agents/pi-embedded-runner/run/attempt.ts index 893bcbc6717..c010d5811d0 100644 --- a/src/agents/pi-embedded-runner/run/attempt.ts +++ b/src/agents/pi-embedded-runner/run/attempt.ts @@ -810,17 +810,6 @@ export async function runEmbeddedAttempt( note: `images: prompt=${imageResult.images.length} history=${imageResult.historyImagesByIndex.size}`, }); - const shouldTrackCacheTtl = - params.config?.agents?.defaults?.contextPruning?.mode === "cache-ttl" && - isCacheTtlEligibleProvider(params.provider, params.modelId); - if (shouldTrackCacheTtl) { - appendCacheTtlTimestamp(sessionManager, { - timestamp: Date.now(), - provider: params.provider, - modelId: params.modelId, - }); - } - // Only pass images option if there are actually images to pass // This avoids potential issues with models that don't expect the images parameter if (imageResult.images.length > 0) { @@ -848,6 +837,22 @@ export async function runEmbeddedAttempt( } } + // Append cache-TTL timestamp AFTER prompt + compaction retry completes. + // Previously this was before the prompt, which caused a custom entry to be + // inserted between compaction and the next prompt — breaking the + // prepareCompaction() guard that checks the last entry type, leading to + // double-compaction. See: https://github.com/openclaw/openclaw/issues/9282 + const shouldTrackCacheTtl = + params.config?.agents?.defaults?.contextPruning?.mode === "cache-ttl" && + isCacheTtlEligibleProvider(params.provider, params.modelId); + if (shouldTrackCacheTtl) { + appendCacheTtlTimestamp(sessionManager, { + timestamp: Date.now(), + provider: params.provider, + modelId: params.modelId, + }); + } + messagesSnapshot = activeSession.messages.slice(); sessionIdUsed = activeSession.sessionId; cacheTrace?.recordStage("session:after", {