From 806397f0d92cd4a2182b025a00e698bf982d45f5 Mon Sep 17 00:00:00 2001 From: mushuiyu886 Date: Mon, 6 Jul 2026 14:34:05 +0800 Subject: [PATCH] Treat already-compacted CLI compaction as no-op (#99136) --- src/agents/command/cli-compaction.test.ts | 68 +++++++++++++++++++++++ src/agents/command/cli-compaction.ts | 22 +++++--- 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/agents/command/cli-compaction.test.ts b/src/agents/command/cli-compaction.test.ts index d4215d73dd94..226d1ef7b398 100644 --- a/src/agents/command/cli-compaction.test.ts +++ b/src/agents/command/cli-compaction.test.ts @@ -273,6 +273,74 @@ describe("runCliTurnCompactionLifecycle", () => { ); }); + it("treats already-compacted CLI transcript compaction as a no-op", async () => { + const sessionKey = "agent:main:qwen-already-compacted"; + const sessionId = "session-qwen-already-compacted"; + const sessionFile = path.join(tmpDir, "session-qwen-already-compacted.jsonl"); + const storePath = path.join(tmpDir, "sessions-qwen-already-compacted.json"); + await writeSessionFile({ sessionFile, sessionId }); + + const sessionEntry: SessionEntry = { + sessionId, + updatedAt: Date.now(), + sessionFile, + contextTokens: 1_000, + totalTokens: 950, + totalTokensFresh: true, + }; + const sessionStore: Record = { [sessionKey]: sessionEntry }; + await fs.writeFile(storePath, JSON.stringify(sessionStore, null, 2), "utf-8"); + + const compactCalls: Array[0]> = []; + const maintenance = vi.fn(async () => ({ changed: false, bytesFreed: 0, rewrittenEntries: 0 })); + const recordCliCompactionInStore = vi.fn(); + setCliCompactionTestDeps({ + resolveContextEngine: async () => ({ + ...buildContextEngine({ compactCalls }), + async compact(compactParams) { + compactCalls.push(compactParams); + throw new Error("Already compacted"); + }, + }), + createPreparedEmbeddedAgentSettingsManager: async () => ({ + getCompactionReserveTokens: () => 200, + getCompactionKeepRecentTokens: () => 0, + applyOverrides: () => {}, + }), + shouldPreemptivelyCompactBeforePrompt: () => ({ + route: "fits", + shouldCompact: false, + estimatedPromptTokens: 600, + promptBudgetBeforeReserve: 800, + overflowTokens: 0, + toolResultReducibleChars: 0, + effectiveReserveTokens: 200, + }), + resolveLiveToolResultMaxChars: () => 20_000, + runContextEngineMaintenance: maintenance, + recordCliCompactionInStore, + }); + + const updatedEntry = await runCliTurnCompactionLifecycle({ + cfg: {} as OpenClawConfig, + sessionId, + sessionKey, + sessionEntry, + sessionStore, + storePath, + sessionAgentId: "main", + workspaceDir: tmpDir, + agentDir: tmpDir, + provider: "ollama", + model: "qwen3:14b", + }); + + expect(compactCalls).toHaveLength(1); + expect(maintenance).not.toHaveBeenCalled(); + expect(recordCliCompactionInStore).not.toHaveBeenCalled(); + expect(updatedEntry).toBe(sessionEntry); + }); + it("routes OpenAI Codex harness CLI compaction through native harness compaction", async () => { const sessionKey = "agent:main:codex"; const sessionId = "session-codex"; diff --git a/src/agents/command/cli-compaction.ts b/src/agents/command/cli-compaction.ts index 153e933905dd..7575302ed7b7 100644 --- a/src/agents/command/cli-compaction.ts +++ b/src/agents/command/cli-compaction.ts @@ -200,8 +200,9 @@ function isUnsupportedNativeHarnessCompaction( return result?.ok === false && result.failure?.reason === "unsupported_harness_compaction"; } -function isBelowCompactionTargetReason(reason: string | undefined): boolean { - return classifyCompactionReason(reason) === "below_threshold"; +function isBenignCliCompactionNoopReason(reason: string | undefined): boolean { + const classification = classifyCompactionReason(reason); + return classification === "below_threshold" || classification === "already_compacted_recently"; } function isIntentionalNativeAutoCompactionSkip( @@ -317,18 +318,23 @@ async function compactCliTranscript(params: { resolveCompactionTimeoutMs(params.cfg), ); } catch (error) { - log.warn( - `CLI transcript compaction failed for ${params.provider}/${params.model}: ${error instanceof Error ? error.message : String(error)}`, - ); + const reason = error instanceof Error ? error.message : String(error); + if (isBenignCliCompactionNoopReason(reason)) { + log.info( + `CLI transcript compaction skipped for ${params.provider}/${params.model}: ${reason}`, + ); + return { compacted: false }; + } + log.warn(`CLI transcript compaction failed for ${params.provider}/${params.model}: ${reason}`); return { compacted: false, - failureReason: error instanceof Error ? error.message : String(error), + failureReason: reason, }; } if (!compactResult.compacted) { const reason = compactResult.reason ?? "nothing to compact"; - if (isBelowCompactionTargetReason(reason)) { + if (isBenignCliCompactionNoopReason(reason)) { log.info( `CLI transcript compaction skipped for ${params.provider}/${params.model}: ${reason}`, ); @@ -466,7 +472,7 @@ async function compactNativeHarnessCliTranscript(params: { if (!result?.compacted) { const reason = result?.reason ?? "nothing to compact"; - if (isBelowCompactionTargetReason(reason)) { + if (isBenignCliCompactionNoopReason(reason)) { log.info( `CLI native harness compaction skipped for ${params.provider}/${params.model}: ${reason}`, );